Branch data Line data Source code
1 : : /*
2 : : * devres.c -- Voltage/Current Regulator framework devres implementation.
3 : : *
4 : : * Copyright 2013 Linaro Ltd
5 : : *
6 : : * This program is free software; you can redistribute it and/or modify it
7 : : * under the terms of the GNU General Public License as published by the
8 : : * Free Software Foundation; either version 2 of the License, or (at your
9 : : * option) any later version.
10 : : *
11 : : */
12 : :
13 : : #include <linux/kernel.h>
14 : : #include <linux/err.h>
15 : : #include <linux/regmap.h>
16 : : #include <linux/regulator/consumer.h>
17 : : #include <linux/regulator/driver.h>
18 : : #include <linux/module.h>
19 : :
20 : : #include "internal.h"
21 : :
22 : : enum {
23 : : NORMAL_GET,
24 : : EXCLUSIVE_GET,
25 : : OPTIONAL_GET,
26 : : };
27 : :
28 : 0 : static void devm_regulator_release(struct device *dev, void *res)
29 : : {
30 : 0 : regulator_put(*(struct regulator **)res);
31 : 0 : }
32 : :
33 : 0 : static struct regulator *_devm_regulator_get(struct device *dev, const char *id,
34 : : int get_type)
35 : : {
36 : : struct regulator **ptr, *regulator;
37 : :
38 : 0 : ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL);
39 [ # # ]: 0 : if (!ptr)
40 : : return ERR_PTR(-ENOMEM);
41 : :
42 [ # # # # ]: 0 : switch (get_type) {
43 : : case NORMAL_GET:
44 : 0 : regulator = regulator_get(dev, id);
45 : 0 : break;
46 : : case EXCLUSIVE_GET:
47 : 0 : regulator = regulator_get_exclusive(dev, id);
48 : 0 : break;
49 : : case OPTIONAL_GET:
50 : 0 : regulator = regulator_get_optional(dev, id);
51 : 0 : break;
52 : : default:
53 : : regulator = ERR_PTR(-EINVAL);
54 : : }
55 : :
56 [ # # ]: 0 : if (!IS_ERR(regulator)) {
57 : 0 : *ptr = regulator;
58 : 0 : devres_add(dev, ptr);
59 : : } else {
60 : 0 : devres_free(ptr);
61 : : }
62 : :
63 : 0 : return regulator;
64 : : }
65 : :
66 : : /**
67 : : * devm_regulator_get - Resource managed regulator_get()
68 : : * @dev: device for regulator "consumer"
69 : : * @id: Supply name or regulator ID.
70 : : *
71 : : * Managed regulator_get(). Regulators returned from this function are
72 : : * automatically regulator_put() on driver detach. See regulator_get() for more
73 : : * information.
74 : : */
75 : 0 : struct regulator *devm_regulator_get(struct device *dev, const char *id)
76 : : {
77 : 0 : return _devm_regulator_get(dev, id, NORMAL_GET);
78 : : }
79 : : EXPORT_SYMBOL_GPL(devm_regulator_get);
80 : :
81 : : /**
82 : : * devm_regulator_get_exclusive - Resource managed regulator_get_exclusive()
83 : : * @dev: device for regulator "consumer"
84 : : * @id: Supply name or regulator ID.
85 : : *
86 : : * Managed regulator_get_exclusive(). Regulators returned from this function
87 : : * are automatically regulator_put() on driver detach. See regulator_get() for
88 : : * more information.
89 : : */
90 : 0 : struct regulator *devm_regulator_get_exclusive(struct device *dev,
91 : : const char *id)
92 : : {
93 : 0 : return _devm_regulator_get(dev, id, EXCLUSIVE_GET);
94 : : }
95 : : EXPORT_SYMBOL_GPL(devm_regulator_get_exclusive);
96 : :
97 : : /**
98 : : * devm_regulator_get_optional - Resource managed regulator_get_optional()
99 : : * @dev: device for regulator "consumer"
100 : : * @id: Supply name or regulator ID.
101 : : *
102 : : * Managed regulator_get_optional(). Regulators returned from this
103 : : * function are automatically regulator_put() on driver detach. See
104 : : * regulator_get_optional() for more information.
105 : : */
106 : 0 : struct regulator *devm_regulator_get_optional(struct device *dev,
107 : : const char *id)
108 : : {
109 : 0 : return _devm_regulator_get(dev, id, OPTIONAL_GET);
110 : : }
111 : : EXPORT_SYMBOL_GPL(devm_regulator_get_optional);
112 : :
113 : 0 : static int devm_regulator_match(struct device *dev, void *res, void *data)
114 : : {
115 : : struct regulator **r = res;
116 [ # # ][ # # ]: 0 : if (!r || !*r) {
117 [ # # ][ # # ]: 0 : WARN_ON(!r || !*r);
[ # # ]
118 : : return 0;
119 : : }
120 : 0 : return *r == data;
121 : : }
122 : :
123 : : /**
124 : : * devm_regulator_put - Resource managed regulator_put()
125 : : * @regulator: regulator to free
126 : : *
127 : : * Deallocate a regulator allocated with devm_regulator_get(). Normally
128 : : * this function will not need to be called and the resource management
129 : : * code will ensure that the resource is freed.
130 : : */
131 : 0 : void devm_regulator_put(struct regulator *regulator)
132 : : {
133 : : int rc;
134 : :
135 : 0 : rc = devres_release(regulator->dev, devm_regulator_release,
136 : : devm_regulator_match, regulator);
137 [ # # ]: 0 : if (rc != 0)
138 [ # # ]: 0 : WARN_ON(rc);
139 : 0 : }
140 : : EXPORT_SYMBOL_GPL(devm_regulator_put);
141 : :
142 : : /**
143 : : * devm_regulator_bulk_get - managed get multiple regulator consumers
144 : : *
145 : : * @dev: Device to supply
146 : : * @num_consumers: Number of consumers to register
147 : : * @consumers: Configuration of consumers; clients are stored here.
148 : : *
149 : : * @return 0 on success, an errno on failure.
150 : : *
151 : : * This helper function allows drivers to get several regulator
152 : : * consumers in one operation with management, the regulators will
153 : : * automatically be freed when the device is unbound. If any of the
154 : : * regulators cannot be acquired then any regulators that were
155 : : * allocated will be freed before returning to the caller.
156 : : */
157 : 0 : int devm_regulator_bulk_get(struct device *dev, int num_consumers,
158 : : struct regulator_bulk_data *consumers)
159 : : {
160 : : int i;
161 : : int ret;
162 : :
163 [ # # ]: 0 : for (i = 0; i < num_consumers; i++)
164 : 0 : consumers[i].consumer = NULL;
165 : :
166 [ # # ]: 0 : for (i = 0; i < num_consumers; i++) {
167 : 0 : consumers[i].consumer = devm_regulator_get(dev,
168 : 0 : consumers[i].supply);
169 [ # # ]: 0 : if (IS_ERR(consumers[i].consumer)) {
170 : : ret = PTR_ERR(consumers[i].consumer);
171 : 0 : dev_err(dev, "Failed to get supply '%s': %d\n",
172 : : consumers[i].supply, ret);
173 : 0 : consumers[i].consumer = NULL;
174 : : goto err;
175 : : }
176 : : }
177 : :
178 : : return 0;
179 : :
180 : : err:
181 [ # # ][ # # ]: 0 : for (i = 0; i < num_consumers && consumers[i].consumer; i++)
182 : 0 : devm_regulator_put(consumers[i].consumer);
183 : :
184 : : return ret;
185 : : }
186 : : EXPORT_SYMBOL_GPL(devm_regulator_bulk_get);
187 : :
188 : 0 : static void devm_rdev_release(struct device *dev, void *res)
189 : : {
190 : 0 : regulator_unregister(*(struct regulator_dev **)res);
191 : 0 : }
192 : :
193 : : /**
194 : : * devm_regulator_register - Resource managed regulator_register()
195 : : * @regulator_desc: regulator to register
196 : : * @config: runtime configuration for regulator
197 : : *
198 : : * Called by regulator drivers to register a regulator. Returns a
199 : : * valid pointer to struct regulator_dev on success or an ERR_PTR() on
200 : : * error. The regulator will automatically be released when the device
201 : : * is unbound.
202 : : */
203 : 0 : struct regulator_dev *devm_regulator_register(struct device *dev,
204 : : const struct regulator_desc *regulator_desc,
205 : : const struct regulator_config *config)
206 : : {
207 : : struct regulator_dev **ptr, *rdev;
208 : :
209 : 0 : ptr = devres_alloc(devm_rdev_release, sizeof(*ptr),
210 : : GFP_KERNEL);
211 [ # # ]: 0 : if (!ptr)
212 : : return ERR_PTR(-ENOMEM);
213 : :
214 : 0 : rdev = regulator_register(regulator_desc, config);
215 [ # # ]: 0 : if (!IS_ERR(rdev)) {
216 : 0 : *ptr = rdev;
217 : 0 : devres_add(dev, ptr);
218 : : } else {
219 : 0 : devres_free(ptr);
220 : : }
221 : :
222 : 0 : return rdev;
223 : : }
224 : : EXPORT_SYMBOL_GPL(devm_regulator_register);
225 : :
226 : 0 : static int devm_rdev_match(struct device *dev, void *res, void *data)
227 : : {
228 : : struct regulator_dev **r = res;
229 [ # # ][ # # ]: 0 : if (!r || !*r) {
230 [ # # ][ # # ]: 0 : WARN_ON(!r || !*r);
[ # # ]
231 : : return 0;
232 : : }
233 : 0 : return *r == data;
234 : : }
235 : :
236 : : /**
237 : : * devm_regulator_unregister - Resource managed regulator_unregister()
238 : : * @regulator: regulator to free
239 : : *
240 : : * Unregister a regulator registered with devm_regulator_register().
241 : : * Normally this function will not need to be called and the resource
242 : : * management code will ensure that the resource is freed.
243 : : */
244 : 0 : void devm_regulator_unregister(struct device *dev, struct regulator_dev *rdev)
245 : : {
246 : : int rc;
247 : :
248 : 0 : rc = devres_release(dev, devm_rdev_release, devm_rdev_match, rdev);
249 [ # # ]: 0 : if (rc != 0)
250 [ # # ]: 0 : WARN_ON(rc);
251 : 0 : }
252 : : EXPORT_SYMBOL_GPL(devm_regulator_unregister);
253 : :
254 : : struct regulator_supply_alias_match {
255 : : struct device *dev;
256 : : const char *id;
257 : : };
258 : :
259 : 0 : static int devm_regulator_match_supply_alias(struct device *dev, void *res,
260 : : void *data)
261 : : {
262 : : struct regulator_supply_alias_match *match = res;
263 : : struct regulator_supply_alias_match *target = data;
264 : :
265 [ # # ][ # # ]: 0 : return match->dev == target->dev && strcmp(match->id, target->id) == 0;
266 : : }
267 : :
268 : 0 : static void devm_regulator_destroy_supply_alias(struct device *dev, void *res)
269 : : {
270 : : struct regulator_supply_alias_match *match = res;
271 : :
272 : 0 : regulator_unregister_supply_alias(match->dev, match->id);
273 : 0 : }
274 : :
275 : : /**
276 : : * devm_regulator_register_supply_alias - Resource managed
277 : : * regulator_register_supply_alias()
278 : : *
279 : : * @dev: device that will be given as the regulator "consumer"
280 : : * @id: Supply name or regulator ID
281 : : * @alias_dev: device that should be used to lookup the supply
282 : : * @alias_id: Supply name or regulator ID that should be used to lookup the
283 : : * supply
284 : : *
285 : : * The supply alias will automatically be unregistered when the source
286 : : * device is unbound.
287 : : */
288 : 0 : int devm_regulator_register_supply_alias(struct device *dev, const char *id,
289 : : struct device *alias_dev,
290 : : const char *alias_id)
291 : : {
292 : : struct regulator_supply_alias_match *match;
293 : : int ret;
294 : :
295 : 0 : match = devres_alloc(devm_regulator_destroy_supply_alias,
296 : : sizeof(struct regulator_supply_alias_match),
297 : : GFP_KERNEL);
298 [ # # ]: 0 : if (!match)
299 : : return -ENOMEM;
300 : :
301 : 0 : match->dev = dev;
302 : 0 : match->id = id;
303 : :
304 : 0 : ret = regulator_register_supply_alias(dev, id, alias_dev, alias_id);
305 [ # # ]: 0 : if (ret < 0) {
306 : 0 : devres_free(match);
307 : 0 : return ret;
308 : : }
309 : :
310 : 0 : devres_add(dev, match);
311 : :
312 : 0 : return 0;
313 : : }
314 : : EXPORT_SYMBOL_GPL(devm_regulator_register_supply_alias);
315 : :
316 : : /**
317 : : * devm_regulator_unregister_supply_alias - Resource managed
318 : : * regulator_unregister_supply_alias()
319 : : *
320 : : * @dev: device that will be given as the regulator "consumer"
321 : : * @id: Supply name or regulator ID
322 : : *
323 : : * Unregister an alias registered with
324 : : * devm_regulator_register_supply_alias(). Normally this function
325 : : * will not need to be called and the resource management code
326 : : * will ensure that the resource is freed.
327 : : */
328 : 0 : void devm_regulator_unregister_supply_alias(struct device *dev, const char *id)
329 : : {
330 : : struct regulator_supply_alias_match match;
331 : : int rc;
332 : :
333 : 0 : match.dev = dev;
334 : 0 : match.id = id;
335 : :
336 : 0 : rc = devres_release(dev, devm_regulator_destroy_supply_alias,
337 : : devm_regulator_match_supply_alias, &match);
338 [ # # ]: 0 : if (rc != 0)
339 [ # # ]: 0 : WARN_ON(rc);
340 : 0 : }
341 : : EXPORT_SYMBOL_GPL(devm_regulator_unregister_supply_alias);
342 : :
343 : : /**
344 : : * devm_regulator_bulk_register_supply_alias - Managed register
345 : : * multiple aliases
346 : : *
347 : : * @dev: device that will be given as the regulator "consumer"
348 : : * @id: List of supply names or regulator IDs
349 : : * @alias_dev: device that should be used to lookup the supply
350 : : * @alias_id: List of supply names or regulator IDs that should be used to
351 : : * lookup the supply
352 : : * @num_id: Number of aliases to register
353 : : *
354 : : * @return 0 on success, an errno on failure.
355 : : *
356 : : * This helper function allows drivers to register several supply
357 : : * aliases in one operation, the aliases will be automatically
358 : : * unregisters when the source device is unbound. If any of the
359 : : * aliases cannot be registered any aliases that were registered
360 : : * will be removed before returning to the caller.
361 : : */
362 : 0 : int devm_regulator_bulk_register_supply_alias(struct device *dev,
363 : : const char **id,
364 : : struct device *alias_dev,
365 : : const char **alias_id,
366 : : int num_id)
367 : : {
368 : : int i;
369 : : int ret;
370 : :
371 [ # # ]: 0 : for (i = 0; i < num_id; ++i) {
372 : 0 : ret = devm_regulator_register_supply_alias(dev, id[i],
373 : : alias_dev,
374 : 0 : alias_id[i]);
375 [ # # ]: 0 : if (ret < 0)
376 : : goto err;
377 : : }
378 : :
379 : : return 0;
380 : :
381 : : err:
382 : 0 : dev_err(dev,
383 : : "Failed to create supply alias %s,%s -> %s,%s\n",
384 : : id[i], dev_name(dev), alias_id[i], dev_name(alias_dev));
385 : :
386 [ # # ]: 0 : while (--i >= 0)
387 : 0 : devm_regulator_unregister_supply_alias(dev, id[i]);
388 : :
389 : : return ret;
390 : : }
391 : : EXPORT_SYMBOL_GPL(devm_regulator_bulk_register_supply_alias);
392 : :
393 : : /**
394 : : * devm_regulator_bulk_unregister_supply_alias - Managed unregister
395 : : * multiple aliases
396 : : *
397 : : * @dev: device that will be given as the regulator "consumer"
398 : : * @id: List of supply names or regulator IDs
399 : : * @num_id: Number of aliases to unregister
400 : : *
401 : : * Unregister aliases registered with
402 : : * devm_regulator_bulk_register_supply_alias(). Normally this function
403 : : * will not need to be called and the resource management code
404 : : * will ensure that the resource is freed.
405 : : */
406 : 0 : void devm_regulator_bulk_unregister_supply_alias(struct device *dev,
407 : : const char **id,
408 : : int num_id)
409 : : {
410 : : int i;
411 : :
412 [ # # ]: 0 : for (i = 0; i < num_id; ++i)
413 : 0 : devm_regulator_unregister_supply_alias(dev, id[i]);
414 : 0 : }
415 : : EXPORT_SYMBOL_GPL(devm_regulator_bulk_unregister_supply_alias);
|