projects/linux·blob master · refs

359 lines · 7.8 KiB

1// SPDX-License-Identifier: GPL-2.0
2#include <linux/clk.h>
3#include <linux/device.h>
4#include <linux/export.h>
5#include <linux/gfp.h>
6
7struct devm_clk_state {
8 struct clk *clk;
9 void (*exit)(struct clk *clk);
10};
11
12static void devm_clk_release(struct device *dev, void *res)
13{
14 struct devm_clk_state *state = res;
15
16 if (state->exit)
17 state->exit(state->clk);
18
19 clk_put(state->clk);
20}
21
22static struct clk *__devm_clk_get(struct device *dev, const char *id,
23 struct clk *(*get)(struct device *dev, const char *id),
24 int (*init)(struct clk *clk),
25 void (*exit)(struct clk *clk))
26{
27 struct devm_clk_state *state;
28 struct clk *clk;
29 int ret;
30
31 state = devres_alloc(devm_clk_release, sizeof(*state), GFP_KERNEL);
32 if (!state)
33 return ERR_PTR(-ENOMEM);
34
35 clk = get(dev, id);
36 if (IS_ERR(clk)) {
37 ret = PTR_ERR(clk);
38 goto err_clk_get;
39 }
40
41 if (init) {
42 ret = init(clk);
43 if (ret)
44 goto err_clk_init;
45 }
46
47 state->clk = clk;
48 state->exit = exit;
49
50 devres_add(dev, state);
51
52 return clk;
53
54err_clk_init:
55
56 clk_put(clk);
57err_clk_get:
58
59 devres_free(state);
60 return ERR_PTR(ret);
61}
62
63struct clk *devm_clk_get(struct device *dev, const char *id)
64{
65 return __devm_clk_get(dev, id, clk_get, NULL, NULL);
66}
67EXPORT_SYMBOL(devm_clk_get);
68
69struct clk *devm_clk_get_prepared(struct device *dev, const char *id)
70{
71 return __devm_clk_get(dev, id, clk_get, clk_prepare, clk_unprepare);
72}
73EXPORT_SYMBOL_GPL(devm_clk_get_prepared);
74
75struct clk *devm_clk_get_enabled(struct device *dev, const char *id)
76{
77 return __devm_clk_get(dev, id, clk_get,
78 clk_prepare_enable, clk_disable_unprepare);
79}
80EXPORT_SYMBOL_GPL(devm_clk_get_enabled);
81
82struct clk *devm_clk_get_optional(struct device *dev, const char *id)
83{
84 return __devm_clk_get(dev, id, clk_get_optional, NULL, NULL);
85}
86EXPORT_SYMBOL(devm_clk_get_optional);
87
88struct clk *devm_clk_get_optional_prepared(struct device *dev, const char *id)
89{
90 return __devm_clk_get(dev, id, clk_get_optional,
91 clk_prepare, clk_unprepare);
92}
93EXPORT_SYMBOL_GPL(devm_clk_get_optional_prepared);
94
95struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id)
96{
97 return __devm_clk_get(dev, id, clk_get_optional,
98 clk_prepare_enable, clk_disable_unprepare);
99}
100EXPORT_SYMBOL_GPL(devm_clk_get_optional_enabled);
101
102static void devm_clk_disable_unprepare(void *data)
103{
104 clk_disable_unprepare(data);
105}
106
107struct clk *devm_clk_get_optional_enabled_with_rate(struct device *dev,
108 const char *id,
109 unsigned long rate)
110{
111 struct clk *clk;
112 int ret;
113
114 clk = devm_clk_get_optional(dev, id);
115 if (IS_ERR(clk))
116 return ERR_CAST(clk);
117
118 ret = clk_set_rate(clk, rate);
119 if (ret)
120 goto out_put_clk;
121
122 ret = clk_prepare_enable(clk);
123 if (ret)
124 goto out_put_clk;
125
126 ret = devm_add_action_or_reset(dev, devm_clk_disable_unprepare, clk);
127 if (ret)
128 goto out_put_clk;
129
130 return clk;
131
132out_put_clk:
133 devm_clk_put(dev, clk);
134 return ERR_PTR(ret);
135}
136EXPORT_SYMBOL_GPL(devm_clk_get_optional_enabled_with_rate);
137
138struct clk_bulk_devres {
139 struct clk_bulk_data *clks;
140 int num_clks;
141};
142
143static void devm_clk_bulk_release(struct device *dev, void *res)
144{
145 struct clk_bulk_devres *devres = res;
146
147 clk_bulk_put(devres->num_clks, devres->clks);
148}
149
150static int __devm_clk_bulk_get(struct device *dev, int num_clks,
151 struct clk_bulk_data *clks, bool optional)
152{
153 struct clk_bulk_devres *devres;
154 int ret;
155
156 devres = devres_alloc(devm_clk_bulk_release,
157 sizeof(*devres), GFP_KERNEL);
158 if (!devres)
159 return -ENOMEM;
160
161 if (optional)
162 ret = clk_bulk_get_optional(dev, num_clks, clks);
163 else
164 ret = clk_bulk_get(dev, num_clks, clks);
165 if (!ret) {
166 devres->clks = clks;
167 devres->num_clks = num_clks;
168 devres_add(dev, devres);
169 } else {
170 devres_free(devres);
171 }
172
173 return ret;
174}
175
176int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
177 struct clk_bulk_data *clks)
178{
179 return __devm_clk_bulk_get(dev, num_clks, clks, false);
180}
181EXPORT_SYMBOL_GPL(devm_clk_bulk_get);
182
183int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks,
184 struct clk_bulk_data *clks)
185{
186 return __devm_clk_bulk_get(dev, num_clks, clks, true);
187}
188EXPORT_SYMBOL_GPL(devm_clk_bulk_get_optional);
189
190static void devm_clk_bulk_release_enable(struct device *dev, void *res)
191{
192 struct clk_bulk_devres *devres = res;
193
194 clk_bulk_disable_unprepare(devres->num_clks, devres->clks);
195 clk_bulk_put(devres->num_clks, devres->clks);
196}
197
198static int __devm_clk_bulk_get_enable(struct device *dev, int num_clks,
199 struct clk_bulk_data *clks, bool optional)
200{
201 struct clk_bulk_devres *devres;
202 int ret;
203
204 devres = devres_alloc(devm_clk_bulk_release_enable,
205 sizeof(*devres), GFP_KERNEL);
206 if (!devres)
207 return -ENOMEM;
208
209 if (optional)
210 ret = clk_bulk_get_optional(dev, num_clks, clks);
211 else
212 ret = clk_bulk_get(dev, num_clks, clks);
213 if (ret)
214 goto err_clk_get;
215
216 ret = clk_bulk_prepare_enable(num_clks, clks);
217 if (ret)
218 goto err_clk_prepare;
219
220 devres->clks = clks;
221 devres->num_clks = num_clks;
222 devres_add(dev, devres);
223
224 return 0;
225
226err_clk_prepare:
227 clk_bulk_put(num_clks, clks);
228err_clk_get:
229 devres_free(devres);
230 return ret;
231}
232
233int __must_check devm_clk_bulk_get_enable(struct device *dev, int num_clks,
234 struct clk_bulk_data *clks)
235{
236 return __devm_clk_bulk_get_enable(dev, num_clks, clks, false);
237}
238EXPORT_SYMBOL_GPL(devm_clk_bulk_get_enable);
239
240int __must_check devm_clk_bulk_get_optional_enable(struct device *dev, int num_clks,
241 struct clk_bulk_data *clks)
242{
243 return __devm_clk_bulk_get_enable(dev, num_clks, clks, true);
244}
245EXPORT_SYMBOL_GPL(devm_clk_bulk_get_optional_enable);
246
247static void devm_clk_bulk_release_all(struct device *dev, void *res)
248{
249 struct clk_bulk_devres *devres = res;
250
251 clk_bulk_put_all(devres->num_clks, devres->clks);
252}
253
254int __must_check devm_clk_bulk_get_all(struct device *dev,
255 struct clk_bulk_data **clks)
256{
257 struct clk_bulk_devres *devres;
258 int ret;
259
260 devres = devres_alloc(devm_clk_bulk_release_all,
261 sizeof(*devres), GFP_KERNEL);
262 if (!devres)
263 return -ENOMEM;
264
265 ret = clk_bulk_get_all(dev, &devres->clks);
266 if (ret > 0) {
267 *clks = devres->clks;
268 devres->num_clks = ret;
269 devres_add(dev, devres);
270 } else {
271 devres_free(devres);
272 }
273
274 return ret;
275}
276EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all);
277
278static void devm_clk_bulk_release_all_enable(struct device *dev, void *res)
279{
280 struct clk_bulk_devres *devres = res;
281
282 clk_bulk_disable_unprepare(devres->num_clks, devres->clks);
283 clk_bulk_put_all(devres->num_clks, devres->clks);
284}
285
286int __must_check devm_clk_bulk_get_all_enabled(struct device *dev,
287 struct clk_bulk_data **clks)
288{
289 struct clk_bulk_devres *devres;
290 int ret;
291
292 devres = devres_alloc(devm_clk_bulk_release_all_enable,
293 sizeof(*devres), GFP_KERNEL);
294 if (!devres)
295 return -ENOMEM;
296
297 ret = clk_bulk_get_all(dev, &devres->clks);
298 if (ret > 0) {
299 *clks = devres->clks;
300 devres->num_clks = ret;
301 } else {
302 devres_free(devres);
303 return ret;
304 }
305
306 ret = clk_bulk_prepare_enable(devres->num_clks, *clks);
307 if (!ret) {
308 devres_add(dev, devres);
309 } else {
310 clk_bulk_put_all(devres->num_clks, devres->clks);
311 devres_free(devres);
312 return ret;
313 }
314
315 return devres->num_clks;
316}
317EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all_enabled);
318
319static int devm_clk_match(struct device *dev, void *res, void *data)
320{
321 struct clk **c = res;
322 if (!c || !*c) {
323 WARN_ON(!c || !*c);
324 return 0;
325 }
326 return *c == data;
327}
328
329void devm_clk_put(struct device *dev, struct clk *clk)
330{
331 int ret;
332
333 ret = devres_release(dev, devm_clk_release, devm_clk_match, clk);
334
335 WARN_ON(ret);
336}
337EXPORT_SYMBOL(devm_clk_put);
338
339struct clk *devm_get_clk_from_child(struct device *dev,
340 struct device_node *np, const char *con_id)
341{
342 struct devm_clk_state *state;
343 struct clk *clk;
344
345 state = devres_alloc(devm_clk_release, sizeof(*state), GFP_KERNEL);
346 if (!state)
347 return ERR_PTR(-ENOMEM);
348
349 clk = of_clk_get_by_name(np, con_id);
350 if (!IS_ERR(clk)) {
351 state->clk = clk;
352 devres_add(dev, state);
353 } else {
354 devres_free(state);
355 }
356
357 return clk;
358}
359EXPORT_SYMBOL(devm_get_clk_from_child);