xref: /linux/drivers/clk/clk-devres.c (revision 502d45774af09f1c681c754c4b7cdfb5d7f72fd9)
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 
7 struct devm_clk_state {
8 	struct clk *clk;
9 	void (*exit)(struct clk *clk);
10 };
11 
devm_clk_release(struct device * dev,void * res)12 static 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 
__devm_clk_get(struct device * dev,const char * id,struct clk * (* get)(struct device * dev,const char * id),int (* init)(struct clk * clk),void (* exit)(struct clk * clk))22 static 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 
54 err_clk_init:
55 
56 	clk_put(clk);
57 err_clk_get:
58 
59 	devres_free(state);
60 	return ERR_PTR(ret);
61 }
62 
devm_clk_get(struct device * dev,const char * id)63 struct clk *devm_clk_get(struct device *dev, const char *id)
64 {
65 	return __devm_clk_get(dev, id, clk_get, NULL, NULL);
66 }
67 EXPORT_SYMBOL(devm_clk_get);
68 
devm_clk_get_prepared(struct device * dev,const char * id)69 struct 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 }
73 EXPORT_SYMBOL_GPL(devm_clk_get_prepared);
74 
devm_clk_get_enabled(struct device * dev,const char * id)75 struct 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 }
80 EXPORT_SYMBOL_GPL(devm_clk_get_enabled);
81 
devm_clk_get_optional(struct device * dev,const char * id)82 struct 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 }
86 EXPORT_SYMBOL(devm_clk_get_optional);
87 
devm_clk_get_optional_prepared(struct device * dev,const char * id)88 struct 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 }
93 EXPORT_SYMBOL_GPL(devm_clk_get_optional_prepared);
94 
devm_clk_get_optional_enabled(struct device * dev,const char * id)95 struct 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 }
100 EXPORT_SYMBOL_GPL(devm_clk_get_optional_enabled);
101 
devm_clk_disable_unprepare(void * data)102 static void devm_clk_disable_unprepare(void *data)
103 {
104 	clk_disable_unprepare(data);
105 }
106 
devm_clk_get_optional_enabled_with_rate(struct device * dev,const char * id,unsigned long rate)107 struct 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 
132 out_put_clk:
133 	devm_clk_put(dev, clk);
134 	return ERR_PTR(ret);
135 }
136 EXPORT_SYMBOL_GPL(devm_clk_get_optional_enabled_with_rate);
137 
138 struct clk_bulk_devres {
139 	struct clk_bulk_data *clks;
140 	int num_clks;
141 };
142 
devm_clk_bulk_release(struct device * dev,void * res)143 static 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 
__devm_clk_bulk_get(struct device * dev,int num_clks,struct clk_bulk_data * clks,bool optional)150 static 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 
devm_clk_bulk_get(struct device * dev,int num_clks,struct clk_bulk_data * clks)176 int __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 }
181 EXPORT_SYMBOL_GPL(devm_clk_bulk_get);
182 
devm_clk_bulk_get_optional(struct device * dev,int num_clks,struct clk_bulk_data * clks)183 int __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 }
188 EXPORT_SYMBOL_GPL(devm_clk_bulk_get_optional);
189 
devm_clk_bulk_release_enable(struct device * dev,void * res)190 static 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 
__devm_clk_bulk_get_enable(struct device * dev,int num_clks,struct clk_bulk_data * clks,bool optional)198 static 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 
226 err_clk_prepare:
227 	clk_bulk_put(num_clks, clks);
228 err_clk_get:
229 	devres_free(devres);
230 	return ret;
231 }
232 
devm_clk_bulk_get_enable(struct device * dev,int num_clks,struct clk_bulk_data * clks)233 int __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 }
238 EXPORT_SYMBOL_GPL(devm_clk_bulk_get_enable);
239 
devm_clk_bulk_get_optional_enable(struct device * dev,int num_clks,struct clk_bulk_data * clks)240 int __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 }
245 EXPORT_SYMBOL_GPL(devm_clk_bulk_get_optional_enable);
246 
devm_clk_bulk_release_all(struct device * dev,void * res)247 static 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 
devm_clk_bulk_get_all(struct device * dev,struct clk_bulk_data ** clks)254 int __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 }
276 EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all);
277 
devm_clk_bulk_release_all_enable(struct device * dev,void * res)278 static 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 
devm_clk_bulk_get_all_enabled(struct device * dev,struct clk_bulk_data ** clks)286 int __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 }
317 EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all_enabled);
318 
devm_clk_match(struct device * dev,void * res,void * data)319 static 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 
devm_clk_put(struct device * dev,struct clk * clk)329 void 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 }
337 EXPORT_SYMBOL(devm_clk_put);
338 
devm_get_clk_from_child(struct device * dev,struct device_node * np,const char * con_id)339 struct 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 }
359 EXPORT_SYMBOL(devm_get_clk_from_child);
360