1 | // SPDX-License-Identifier: GPL-2.0-or-later |
---|---|
2 | // |
3 | // helpers.c -- Voltage/Current Regulator framework helper functions. |
4 | // |
5 | // Copyright 2007, 2008 Wolfson Microelectronics PLC. |
6 | // Copyright 2008 SlimLogic Ltd. |
7 | |
8 | #include <linux/bitops.h> |
9 | #include <linux/delay.h> |
10 | #include <linux/err.h> |
11 | #include <linux/export.h> |
12 | #include <linux/kernel.h> |
13 | #include <linux/regmap.h> |
14 | #include <linux/regulator/consumer.h> |
15 | #include <linux/regulator/driver.h> |
16 | |
17 | #include "internal.h" |
18 | |
19 | /** |
20 | * regulator_is_enabled_regmap - standard is_enabled() for regmap users |
21 | * |
22 | * @rdev: regulator to operate on |
23 | * |
24 | * Regulators that use regmap for their register I/O can set the |
25 | * enable_reg and enable_mask fields in their descriptor and then use |
26 | * this as their is_enabled operation, saving some code. |
27 | */ |
28 | int regulator_is_enabled_regmap(struct regulator_dev *rdev) |
29 | { |
30 | unsigned int val; |
31 | int ret; |
32 | |
33 | ret = regmap_read(map: rdev->regmap, reg: rdev->desc->enable_reg, val: &val); |
34 | if (ret != 0) |
35 | return ret; |
36 | |
37 | val &= rdev->desc->enable_mask; |
38 | |
39 | if (rdev->desc->enable_is_inverted) { |
40 | if (rdev->desc->enable_val) |
41 | return val != rdev->desc->enable_val; |
42 | return val == 0; |
43 | } else { |
44 | if (rdev->desc->enable_val) |
45 | return val == rdev->desc->enable_val; |
46 | return val != 0; |
47 | } |
48 | } |
49 | EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap); |
50 | |
51 | /** |
52 | * regulator_enable_regmap - standard enable() for regmap users |
53 | * |
54 | * @rdev: regulator to operate on |
55 | * |
56 | * Regulators that use regmap for their register I/O can set the |
57 | * enable_reg and enable_mask fields in their descriptor and then use |
58 | * this as their enable() operation, saving some code. |
59 | */ |
60 | int regulator_enable_regmap(struct regulator_dev *rdev) |
61 | { |
62 | unsigned int val; |
63 | |
64 | if (rdev->desc->enable_is_inverted) { |
65 | val = rdev->desc->disable_val; |
66 | } else { |
67 | val = rdev->desc->enable_val; |
68 | if (!val) |
69 | val = rdev->desc->enable_mask; |
70 | } |
71 | |
72 | return regmap_update_bits(map: rdev->regmap, reg: rdev->desc->enable_reg, |
73 | mask: rdev->desc->enable_mask, val); |
74 | } |
75 | EXPORT_SYMBOL_GPL(regulator_enable_regmap); |
76 | |
77 | /** |
78 | * regulator_disable_regmap - standard disable() for regmap users |
79 | * |
80 | * @rdev: regulator to operate on |
81 | * |
82 | * Regulators that use regmap for their register I/O can set the |
83 | * enable_reg and enable_mask fields in their descriptor and then use |
84 | * this as their disable() operation, saving some code. |
85 | */ |
86 | int regulator_disable_regmap(struct regulator_dev *rdev) |
87 | { |
88 | unsigned int val; |
89 | |
90 | if (rdev->desc->enable_is_inverted) { |
91 | val = rdev->desc->enable_val; |
92 | if (!val) |
93 | val = rdev->desc->enable_mask; |
94 | } else { |
95 | val = rdev->desc->disable_val; |
96 | } |
97 | |
98 | return regmap_update_bits(map: rdev->regmap, reg: rdev->desc->enable_reg, |
99 | mask: rdev->desc->enable_mask, val); |
100 | } |
101 | EXPORT_SYMBOL_GPL(regulator_disable_regmap); |
102 | |
103 | static int regulator_range_selector_to_index(struct regulator_dev *rdev, |
104 | unsigned int rval) |
105 | { |
106 | int i; |
107 | |
108 | if (!rdev->desc->linear_range_selectors_bitfield) |
109 | return -EINVAL; |
110 | |
111 | rval &= rdev->desc->vsel_range_mask; |
112 | rval >>= ffs(rdev->desc->vsel_range_mask) - 1; |
113 | |
114 | for (i = 0; i < rdev->desc->n_linear_ranges; i++) { |
115 | if (rdev->desc->linear_range_selectors_bitfield[i] == rval) |
116 | return i; |
117 | } |
118 | return -EINVAL; |
119 | } |
120 | |
121 | /** |
122 | * regulator_get_voltage_sel_pickable_regmap - pickable range get_voltage_sel |
123 | * |
124 | * @rdev: regulator to operate on |
125 | * |
126 | * Regulators that use regmap for their register I/O and use pickable |
127 | * ranges can set the vsel_reg, vsel_mask, vsel_range_reg and vsel_range_mask |
128 | * fields in their descriptor and then use this as their get_voltage_sel |
129 | * operation, saving some code. |
130 | */ |
131 | int regulator_get_voltage_sel_pickable_regmap(struct regulator_dev *rdev) |
132 | { |
133 | unsigned int r_val; |
134 | int range; |
135 | unsigned int val; |
136 | int ret; |
137 | unsigned int voltages = 0; |
138 | const struct linear_range *r = rdev->desc->linear_ranges; |
139 | |
140 | if (!r) |
141 | return -EINVAL; |
142 | |
143 | ret = regmap_read(map: rdev->regmap, reg: rdev->desc->vsel_reg, val: &val); |
144 | if (ret != 0) |
145 | return ret; |
146 | |
147 | ret = regmap_read(map: rdev->regmap, reg: rdev->desc->vsel_range_reg, val: &r_val); |
148 | if (ret != 0) |
149 | return ret; |
150 | |
151 | val &= rdev->desc->vsel_mask; |
152 | val >>= ffs(rdev->desc->vsel_mask) - 1; |
153 | |
154 | range = regulator_range_selector_to_index(rdev, rval: r_val); |
155 | if (range < 0) |
156 | return -EINVAL; |
157 | |
158 | voltages = linear_range_values_in_range_array(r, ranges: range); |
159 | |
160 | return val + voltages; |
161 | } |
162 | EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_pickable_regmap); |
163 | |
164 | static int write_separate_vsel_and_range(struct regulator_dev *rdev, |
165 | unsigned int sel, unsigned int range) |
166 | { |
167 | bool range_updated; |
168 | int ret; |
169 | |
170 | ret = regmap_update_bits_base(map: rdev->regmap, reg: rdev->desc->vsel_range_reg, |
171 | mask: rdev->desc->vsel_range_mask, |
172 | val: range, change: &range_updated, async: false, force: false); |
173 | if (ret) |
174 | return ret; |
175 | |
176 | /* |
177 | * Some PMICs treat the vsel_reg same as apply-bit. Force it to be |
178 | * written if the range changed, even if the old selector was same as |
179 | * the new one |
180 | */ |
181 | if (rdev->desc->range_applied_by_vsel && range_updated) |
182 | return regmap_write_bits(map: rdev->regmap, |
183 | reg: rdev->desc->vsel_reg, |
184 | mask: rdev->desc->vsel_mask, val: sel); |
185 | |
186 | return regmap_update_bits(map: rdev->regmap, reg: rdev->desc->vsel_reg, |
187 | mask: rdev->desc->vsel_mask, val: sel); |
188 | } |
189 | |
190 | /** |
191 | * regulator_set_voltage_sel_pickable_regmap - pickable range set_voltage_sel |
192 | * |
193 | * @rdev: regulator to operate on |
194 | * @sel: Selector to set |
195 | * |
196 | * Regulators that use regmap for their register I/O and use pickable |
197 | * ranges can set the vsel_reg, vsel_mask, vsel_range_reg and vsel_range_mask |
198 | * fields in their descriptor and then use this as their set_voltage_sel |
199 | * operation, saving some code. |
200 | */ |
201 | int regulator_set_voltage_sel_pickable_regmap(struct regulator_dev *rdev, |
202 | unsigned int sel) |
203 | { |
204 | unsigned int range; |
205 | int ret, i; |
206 | unsigned int voltages_in_range = 0; |
207 | |
208 | for (i = 0; i < rdev->desc->n_linear_ranges; i++) { |
209 | const struct linear_range *r; |
210 | |
211 | r = &rdev->desc->linear_ranges[i]; |
212 | voltages_in_range = linear_range_values_in_range(r); |
213 | |
214 | if (sel < voltages_in_range) |
215 | break; |
216 | sel -= voltages_in_range; |
217 | } |
218 | |
219 | if (i == rdev->desc->n_linear_ranges) |
220 | return -EINVAL; |
221 | |
222 | sel <<= ffs(rdev->desc->vsel_mask) - 1; |
223 | sel += rdev->desc->linear_ranges[i].min_sel; |
224 | |
225 | range = rdev->desc->linear_range_selectors_bitfield[i]; |
226 | range <<= ffs(rdev->desc->vsel_range_mask) - 1; |
227 | |
228 | if (rdev->desc->vsel_reg == rdev->desc->vsel_range_reg) |
229 | ret = regmap_update_bits(map: rdev->regmap, reg: rdev->desc->vsel_reg, |
230 | mask: rdev->desc->vsel_range_mask | |
231 | rdev->desc->vsel_mask, val: sel | range); |
232 | else |
233 | ret = write_separate_vsel_and_range(rdev, sel, range); |
234 | |
235 | if (ret) |
236 | return ret; |
237 | |
238 | if (rdev->desc->apply_bit) |
239 | ret = regmap_update_bits(map: rdev->regmap, reg: rdev->desc->apply_reg, |
240 | mask: rdev->desc->apply_bit, |
241 | val: rdev->desc->apply_bit); |
242 | return ret; |
243 | } |
244 | EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_pickable_regmap); |
245 | |
246 | /** |
247 | * regulator_get_voltage_sel_regmap - standard get_voltage_sel for regmap users |
248 | * |
249 | * @rdev: regulator to operate on |
250 | * |
251 | * Regulators that use regmap for their register I/O can set the |
252 | * vsel_reg and vsel_mask fields in their descriptor and then use this |
253 | * as their get_voltage_sel operation, saving some code. |
254 | */ |
255 | int regulator_get_voltage_sel_regmap(struct regulator_dev *rdev) |
256 | { |
257 | unsigned int val; |
258 | int ret; |
259 | |
260 | ret = regmap_read(map: rdev->regmap, reg: rdev->desc->vsel_reg, val: &val); |
261 | if (ret != 0) |
262 | return ret; |
263 | |
264 | val &= rdev->desc->vsel_mask; |
265 | val >>= ffs(rdev->desc->vsel_mask) - 1; |
266 | |
267 | return val; |
268 | } |
269 | EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_regmap); |
270 | |
271 | /** |
272 | * regulator_set_voltage_sel_regmap - standard set_voltage_sel for regmap users |
273 | * |
274 | * @rdev: regulator to operate on |
275 | * @sel: Selector to set |
276 | * |
277 | * Regulators that use regmap for their register I/O can set the |
278 | * vsel_reg and vsel_mask fields in their descriptor and then use this |
279 | * as their set_voltage_sel operation, saving some code. |
280 | */ |
281 | int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel) |
282 | { |
283 | int ret; |
284 | |
285 | sel <<= ffs(rdev->desc->vsel_mask) - 1; |
286 | |
287 | ret = regmap_update_bits(map: rdev->regmap, reg: rdev->desc->vsel_reg, |
288 | mask: rdev->desc->vsel_mask, val: sel); |
289 | if (ret) |
290 | return ret; |
291 | |
292 | if (rdev->desc->apply_bit) |
293 | ret = regmap_update_bits(map: rdev->regmap, reg: rdev->desc->apply_reg, |
294 | mask: rdev->desc->apply_bit, |
295 | val: rdev->desc->apply_bit); |
296 | return ret; |
297 | } |
298 | EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_regmap); |
299 | |
300 | /** |
301 | * regulator_map_voltage_iterate - map_voltage() based on list_voltage() |
302 | * |
303 | * @rdev: Regulator to operate on |
304 | * @min_uV: Lower bound for voltage |
305 | * @max_uV: Upper bound for voltage |
306 | * |
307 | * Drivers implementing set_voltage_sel() and list_voltage() can use |
308 | * this as their map_voltage() operation. It will find a suitable |
309 | * voltage by calling list_voltage() until it gets something in bounds |
310 | * for the requested voltages. |
311 | */ |
312 | int regulator_map_voltage_iterate(struct regulator_dev *rdev, |
313 | int min_uV, int max_uV) |
314 | { |
315 | int best_val = INT_MAX; |
316 | int selector = 0; |
317 | int i, ret; |
318 | |
319 | /* Find the smallest voltage that falls within the specified |
320 | * range. |
321 | */ |
322 | for (i = 0; i < rdev->desc->n_voltages; i++) { |
323 | ret = rdev->desc->ops->list_voltage(rdev, i); |
324 | if (ret < 0) |
325 | continue; |
326 | |
327 | if (ret < best_val && ret >= min_uV && ret <= max_uV) { |
328 | best_val = ret; |
329 | selector = i; |
330 | } |
331 | } |
332 | |
333 | if (best_val != INT_MAX) |
334 | return selector; |
335 | else |
336 | return -EINVAL; |
337 | } |
338 | EXPORT_SYMBOL_GPL(regulator_map_voltage_iterate); |
339 | |
340 | /** |
341 | * regulator_map_voltage_ascend - map_voltage() for ascendant voltage list |
342 | * |
343 | * @rdev: Regulator to operate on |
344 | * @min_uV: Lower bound for voltage |
345 | * @max_uV: Upper bound for voltage |
346 | * |
347 | * Drivers that have ascendant voltage list can use this as their |
348 | * map_voltage() operation. |
349 | */ |
350 | int regulator_map_voltage_ascend(struct regulator_dev *rdev, |
351 | int min_uV, int max_uV) |
352 | { |
353 | int i, ret; |
354 | |
355 | for (i = 0; i < rdev->desc->n_voltages; i++) { |
356 | ret = rdev->desc->ops->list_voltage(rdev, i); |
357 | if (ret < 0) |
358 | continue; |
359 | |
360 | if (ret > max_uV) |
361 | break; |
362 | |
363 | if (ret >= min_uV && ret <= max_uV) |
364 | return i; |
365 | } |
366 | |
367 | return -EINVAL; |
368 | } |
369 | EXPORT_SYMBOL_GPL(regulator_map_voltage_ascend); |
370 | |
371 | /** |
372 | * regulator_map_voltage_linear - map_voltage() for simple linear mappings |
373 | * |
374 | * @rdev: Regulator to operate on |
375 | * @min_uV: Lower bound for voltage |
376 | * @max_uV: Upper bound for voltage |
377 | * |
378 | * Drivers providing min_uV and uV_step in their regulator_desc can |
379 | * use this as their map_voltage() operation. |
380 | */ |
381 | int regulator_map_voltage_linear(struct regulator_dev *rdev, |
382 | int min_uV, int max_uV) |
383 | { |
384 | int ret, voltage; |
385 | |
386 | /* Allow uV_step to be 0 for fixed voltage */ |
387 | if (rdev->desc->n_voltages == 1 && rdev->desc->uV_step == 0) { |
388 | if (min_uV <= rdev->desc->min_uV && rdev->desc->min_uV <= max_uV) |
389 | return 0; |
390 | else |
391 | return -EINVAL; |
392 | } |
393 | |
394 | if (!rdev->desc->uV_step) { |
395 | BUG_ON(!rdev->desc->uV_step); |
396 | return -EINVAL; |
397 | } |
398 | |
399 | if (min_uV < rdev->desc->min_uV) |
400 | min_uV = rdev->desc->min_uV; |
401 | |
402 | ret = DIV_ROUND_UP(min_uV - rdev->desc->min_uV, rdev->desc->uV_step); |
403 | if (ret < 0) |
404 | return ret; |
405 | |
406 | ret += rdev->desc->linear_min_sel; |
407 | |
408 | /* Map back into a voltage to verify we're still in bounds */ |
409 | voltage = rdev->desc->ops->list_voltage(rdev, ret); |
410 | if (voltage < min_uV || voltage > max_uV) |
411 | return -EINVAL; |
412 | |
413 | return ret; |
414 | } |
415 | EXPORT_SYMBOL_GPL(regulator_map_voltage_linear); |
416 | |
417 | /** |
418 | * regulator_map_voltage_linear_range - map_voltage() for multiple linear ranges |
419 | * |
420 | * @rdev: Regulator to operate on |
421 | * @min_uV: Lower bound for voltage |
422 | * @max_uV: Upper bound for voltage |
423 | * |
424 | * Drivers providing linear_ranges in their descriptor can use this as |
425 | * their map_voltage() callback. |
426 | */ |
427 | int regulator_map_voltage_linear_range(struct regulator_dev *rdev, |
428 | int min_uV, int max_uV) |
429 | { |
430 | const struct linear_range *range; |
431 | int ret = -EINVAL; |
432 | unsigned int sel; |
433 | bool found; |
434 | int voltage, i; |
435 | |
436 | if (!rdev->desc->n_linear_ranges) { |
437 | BUG_ON(!rdev->desc->n_linear_ranges); |
438 | return -EINVAL; |
439 | } |
440 | |
441 | for (i = 0; i < rdev->desc->n_linear_ranges; i++) { |
442 | range = &rdev->desc->linear_ranges[i]; |
443 | |
444 | ret = linear_range_get_selector_high(r: range, val: min_uV, selector: &sel, |
445 | found: &found); |
446 | if (ret) |
447 | continue; |
448 | ret = sel; |
449 | |
450 | /* |
451 | * Map back into a voltage to verify we're still in bounds. |
452 | * If we are not, then continue checking rest of the ranges. |
453 | */ |
454 | voltage = rdev->desc->ops->list_voltage(rdev, sel); |
455 | if (voltage >= min_uV && voltage <= max_uV) |
456 | break; |
457 | } |
458 | |
459 | if (i == rdev->desc->n_linear_ranges) |
460 | return -EINVAL; |
461 | |
462 | return ret; |
463 | } |
464 | EXPORT_SYMBOL_GPL(regulator_map_voltage_linear_range); |
465 | |
466 | /** |
467 | * regulator_map_voltage_pickable_linear_range - map_voltage, pickable ranges |
468 | * |
469 | * @rdev: Regulator to operate on |
470 | * @min_uV: Lower bound for voltage |
471 | * @max_uV: Upper bound for voltage |
472 | * |
473 | * Drivers providing pickable linear_ranges in their descriptor can use |
474 | * this as their map_voltage() callback. |
475 | */ |
476 | int regulator_map_voltage_pickable_linear_range(struct regulator_dev *rdev, |
477 | int min_uV, int max_uV) |
478 | { |
479 | const struct linear_range *range; |
480 | int ret = -EINVAL; |
481 | int voltage, i; |
482 | unsigned int selector = 0; |
483 | |
484 | if (!rdev->desc->n_linear_ranges) { |
485 | BUG_ON(!rdev->desc->n_linear_ranges); |
486 | return -EINVAL; |
487 | } |
488 | |
489 | for (i = 0; i < rdev->desc->n_linear_ranges; i++) { |
490 | int linear_max_uV; |
491 | bool found; |
492 | unsigned int sel; |
493 | |
494 | range = &rdev->desc->linear_ranges[i]; |
495 | linear_max_uV = linear_range_get_max_value(r: range); |
496 | |
497 | if (!(min_uV <= linear_max_uV && max_uV >= range->min)) { |
498 | selector += linear_range_values_in_range(r: range); |
499 | continue; |
500 | } |
501 | |
502 | ret = linear_range_get_selector_high(r: range, val: min_uV, selector: &sel, |
503 | found: &found); |
504 | if (ret) { |
505 | selector += linear_range_values_in_range(r: range); |
506 | continue; |
507 | } |
508 | |
509 | ret = selector + sel - range->min_sel; |
510 | |
511 | voltage = rdev->desc->ops->list_voltage(rdev, ret); |
512 | |
513 | /* |
514 | * Map back into a voltage to verify we're still in bounds. |
515 | * We may have overlapping voltage ranges. Hence we don't |
516 | * exit but retry until we have checked all ranges. |
517 | */ |
518 | if (voltage < min_uV || voltage > max_uV) |
519 | selector += linear_range_values_in_range(r: range); |
520 | else |
521 | break; |
522 | } |
523 | |
524 | if (i == rdev->desc->n_linear_ranges) |
525 | return -EINVAL; |
526 | |
527 | return ret; |
528 | } |
529 | EXPORT_SYMBOL_GPL(regulator_map_voltage_pickable_linear_range); |
530 | |
531 | /** |
532 | * regulator_desc_list_voltage_linear - List voltages with simple calculation |
533 | * |
534 | * @desc: Regulator desc for regulator which volatges are to be listed |
535 | * @selector: Selector to convert into a voltage |
536 | * |
537 | * Regulators with a simple linear mapping between voltages and |
538 | * selectors can set min_uV and uV_step in the regulator descriptor |
539 | * and then use this function prior regulator registration to list |
540 | * the voltages. This is useful when voltages need to be listed during |
541 | * device-tree parsing. |
542 | */ |
543 | int regulator_desc_list_voltage_linear(const struct regulator_desc *desc, |
544 | unsigned int selector) |
545 | { |
546 | if (selector >= desc->n_voltages) |
547 | return -EINVAL; |
548 | |
549 | if (selector < desc->linear_min_sel) |
550 | return 0; |
551 | |
552 | selector -= desc->linear_min_sel; |
553 | |
554 | return desc->min_uV + (desc->uV_step * selector); |
555 | } |
556 | EXPORT_SYMBOL_GPL(regulator_desc_list_voltage_linear); |
557 | |
558 | /** |
559 | * regulator_list_voltage_linear - List voltages with simple calculation |
560 | * |
561 | * @rdev: Regulator device |
562 | * @selector: Selector to convert into a voltage |
563 | * |
564 | * Regulators with a simple linear mapping between voltages and |
565 | * selectors can set min_uV and uV_step in the regulator descriptor |
566 | * and then use this function as their list_voltage() operation, |
567 | */ |
568 | int regulator_list_voltage_linear(struct regulator_dev *rdev, |
569 | unsigned int selector) |
570 | { |
571 | return regulator_desc_list_voltage_linear(rdev->desc, selector); |
572 | } |
573 | EXPORT_SYMBOL_GPL(regulator_list_voltage_linear); |
574 | |
575 | /** |
576 | * regulator_list_voltage_pickable_linear_range - pickable range list voltages |
577 | * |
578 | * @rdev: Regulator device |
579 | * @selector: Selector to convert into a voltage |
580 | * |
581 | * list_voltage() operation, intended to be used by drivers utilizing pickable |
582 | * ranges helpers. |
583 | */ |
584 | int regulator_list_voltage_pickable_linear_range(struct regulator_dev *rdev, |
585 | unsigned int selector) |
586 | { |
587 | const struct linear_range *range; |
588 | int i; |
589 | unsigned int all_sels = 0; |
590 | |
591 | if (!rdev->desc->n_linear_ranges) { |
592 | BUG_ON(!rdev->desc->n_linear_ranges); |
593 | return -EINVAL; |
594 | } |
595 | |
596 | for (i = 0; i < rdev->desc->n_linear_ranges; i++) { |
597 | unsigned int sel_indexes; |
598 | |
599 | range = &rdev->desc->linear_ranges[i]; |
600 | |
601 | sel_indexes = linear_range_values_in_range(r: range) - 1; |
602 | |
603 | if (all_sels + sel_indexes >= selector) { |
604 | selector -= all_sels; |
605 | /* |
606 | * As we see here, pickable ranges work only as |
607 | * long as the first selector for each pickable |
608 | * range is 0, and the each subsequent range for |
609 | * this 'pick' follow immediately at next unused |
610 | * selector (Eg. there is no gaps between ranges). |
611 | * I think this is fine but it probably should be |
612 | * documented. OTOH, whole pickable range stuff |
613 | * might benefit from some documentation |
614 | */ |
615 | return range->min + (range->step * selector); |
616 | } |
617 | |
618 | all_sels += (sel_indexes + 1); |
619 | } |
620 | |
621 | return -EINVAL; |
622 | } |
623 | EXPORT_SYMBOL_GPL(regulator_list_voltage_pickable_linear_range); |
624 | |
625 | /** |
626 | * regulator_desc_list_voltage_linear_range - List voltages for linear ranges |
627 | * |
628 | * @desc: Regulator desc for regulator which volatges are to be listed |
629 | * @selector: Selector to convert into a voltage |
630 | * |
631 | * Regulators with a series of simple linear mappings between voltages |
632 | * and selectors who have set linear_ranges in the regulator descriptor |
633 | * can use this function prior regulator registration to list voltages. |
634 | * This is useful when voltages need to be listed during device-tree |
635 | * parsing. |
636 | */ |
637 | int regulator_desc_list_voltage_linear_range(const struct regulator_desc *desc, |
638 | unsigned int selector) |
639 | { |
640 | unsigned int val; |
641 | int ret; |
642 | |
643 | BUG_ON(!desc->n_linear_ranges); |
644 | |
645 | ret = linear_range_get_value_array(r: desc->linear_ranges, |
646 | ranges: desc->n_linear_ranges, selector, |
647 | val: &val); |
648 | if (ret) |
649 | return ret; |
650 | |
651 | return val; |
652 | } |
653 | EXPORT_SYMBOL_GPL(regulator_desc_list_voltage_linear_range); |
654 | |
655 | /** |
656 | * regulator_list_voltage_linear_range - List voltages for linear ranges |
657 | * |
658 | * @rdev: Regulator device |
659 | * @selector: Selector to convert into a voltage |
660 | * |
661 | * Regulators with a series of simple linear mappings between voltages |
662 | * and selectors can set linear_ranges in the regulator descriptor and |
663 | * then use this function as their list_voltage() operation, |
664 | */ |
665 | int regulator_list_voltage_linear_range(struct regulator_dev *rdev, |
666 | unsigned int selector) |
667 | { |
668 | return regulator_desc_list_voltage_linear_range(rdev->desc, selector); |
669 | } |
670 | EXPORT_SYMBOL_GPL(regulator_list_voltage_linear_range); |
671 | |
672 | /** |
673 | * regulator_list_voltage_table - List voltages with table based mapping |
674 | * |
675 | * @rdev: Regulator device |
676 | * @selector: Selector to convert into a voltage |
677 | * |
678 | * Regulators with table based mapping between voltages and |
679 | * selectors can set volt_table in the regulator descriptor |
680 | * and then use this function as their list_voltage() operation. |
681 | */ |
682 | int regulator_list_voltage_table(struct regulator_dev *rdev, |
683 | unsigned int selector) |
684 | { |
685 | if (!rdev->desc->volt_table) { |
686 | BUG_ON(!rdev->desc->volt_table); |
687 | return -EINVAL; |
688 | } |
689 | |
690 | if (selector >= rdev->desc->n_voltages) |
691 | return -EINVAL; |
692 | if (selector < rdev->desc->linear_min_sel) |
693 | return 0; |
694 | |
695 | return rdev->desc->volt_table[selector]; |
696 | } |
697 | EXPORT_SYMBOL_GPL(regulator_list_voltage_table); |
698 | |
699 | /** |
700 | * regulator_set_bypass_regmap - Default set_bypass() using regmap |
701 | * |
702 | * @rdev: device to operate on. |
703 | * @enable: state to set. |
704 | */ |
705 | int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable) |
706 | { |
707 | unsigned int val; |
708 | |
709 | if (enable) { |
710 | val = rdev->desc->bypass_val_on; |
711 | if (!val) |
712 | val = rdev->desc->bypass_mask; |
713 | } else { |
714 | val = rdev->desc->bypass_val_off; |
715 | } |
716 | |
717 | return regmap_update_bits(map: rdev->regmap, reg: rdev->desc->bypass_reg, |
718 | mask: rdev->desc->bypass_mask, val); |
719 | } |
720 | EXPORT_SYMBOL_GPL(regulator_set_bypass_regmap); |
721 | |
722 | /** |
723 | * regulator_set_soft_start_regmap - Default set_soft_start() using regmap |
724 | * |
725 | * @rdev: device to operate on. |
726 | */ |
727 | int regulator_set_soft_start_regmap(struct regulator_dev *rdev) |
728 | { |
729 | unsigned int val; |
730 | |
731 | val = rdev->desc->soft_start_val_on; |
732 | if (!val) |
733 | val = rdev->desc->soft_start_mask; |
734 | |
735 | return regmap_update_bits(map: rdev->regmap, reg: rdev->desc->soft_start_reg, |
736 | mask: rdev->desc->soft_start_mask, val); |
737 | } |
738 | EXPORT_SYMBOL_GPL(regulator_set_soft_start_regmap); |
739 | |
740 | /** |
741 | * regulator_set_pull_down_regmap - Default set_pull_down() using regmap |
742 | * |
743 | * @rdev: device to operate on. |
744 | */ |
745 | int regulator_set_pull_down_regmap(struct regulator_dev *rdev) |
746 | { |
747 | unsigned int val; |
748 | |
749 | val = rdev->desc->pull_down_val_on; |
750 | if (!val) |
751 | val = rdev->desc->pull_down_mask; |
752 | |
753 | return regmap_update_bits(map: rdev->regmap, reg: rdev->desc->pull_down_reg, |
754 | mask: rdev->desc->pull_down_mask, val); |
755 | } |
756 | EXPORT_SYMBOL_GPL(regulator_set_pull_down_regmap); |
757 | |
758 | /** |
759 | * regulator_get_bypass_regmap - Default get_bypass() using regmap |
760 | * |
761 | * @rdev: device to operate on. |
762 | * @enable: current state. |
763 | */ |
764 | int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable) |
765 | { |
766 | unsigned int val; |
767 | unsigned int val_on = rdev->desc->bypass_val_on; |
768 | int ret; |
769 | |
770 | ret = regmap_read(map: rdev->regmap, reg: rdev->desc->bypass_reg, val: &val); |
771 | if (ret != 0) |
772 | return ret; |
773 | |
774 | if (!val_on) |
775 | val_on = rdev->desc->bypass_mask; |
776 | |
777 | *enable = (val & rdev->desc->bypass_mask) == val_on; |
778 | |
779 | return 0; |
780 | } |
781 | EXPORT_SYMBOL_GPL(regulator_get_bypass_regmap); |
782 | |
783 | /** |
784 | * regulator_set_active_discharge_regmap - Default set_active_discharge() |
785 | * using regmap |
786 | * |
787 | * @rdev: device to operate on. |
788 | * @enable: state to set, 0 to disable and 1 to enable. |
789 | */ |
790 | int regulator_set_active_discharge_regmap(struct regulator_dev *rdev, |
791 | bool enable) |
792 | { |
793 | unsigned int val; |
794 | |
795 | if (enable) |
796 | val = rdev->desc->active_discharge_on; |
797 | else |
798 | val = rdev->desc->active_discharge_off; |
799 | |
800 | return regmap_update_bits(map: rdev->regmap, |
801 | reg: rdev->desc->active_discharge_reg, |
802 | mask: rdev->desc->active_discharge_mask, val); |
803 | } |
804 | EXPORT_SYMBOL_GPL(regulator_set_active_discharge_regmap); |
805 | |
806 | /** |
807 | * regulator_set_current_limit_regmap - set_current_limit for regmap users |
808 | * |
809 | * @rdev: regulator to operate on |
810 | * @min_uA: Lower bound for current limit |
811 | * @max_uA: Upper bound for current limit |
812 | * |
813 | * Regulators that use regmap for their register I/O can set curr_table, |
814 | * csel_reg and csel_mask fields in their descriptor and then use this |
815 | * as their set_current_limit operation, saving some code. |
816 | */ |
817 | int regulator_set_current_limit_regmap(struct regulator_dev *rdev, |
818 | int min_uA, int max_uA) |
819 | { |
820 | unsigned int n_currents = rdev->desc->n_current_limits; |
821 | int i, sel = -1; |
822 | |
823 | if (n_currents == 0) |
824 | return -EINVAL; |
825 | |
826 | if (rdev->desc->curr_table) { |
827 | const unsigned int *curr_table = rdev->desc->curr_table; |
828 | bool ascend = curr_table[n_currents - 1] > curr_table[0]; |
829 | |
830 | /* search for closest to maximum */ |
831 | if (ascend) { |
832 | for (i = n_currents - 1; i >= 0; i--) { |
833 | if (min_uA <= curr_table[i] && |
834 | curr_table[i] <= max_uA) { |
835 | sel = i; |
836 | break; |
837 | } |
838 | } |
839 | } else { |
840 | for (i = 0; i < n_currents; i++) { |
841 | if (min_uA <= curr_table[i] && |
842 | curr_table[i] <= max_uA) { |
843 | sel = i; |
844 | break; |
845 | } |
846 | } |
847 | } |
848 | } |
849 | |
850 | if (sel < 0) |
851 | return -EINVAL; |
852 | |
853 | sel <<= ffs(rdev->desc->csel_mask) - 1; |
854 | |
855 | return regmap_update_bits(map: rdev->regmap, reg: rdev->desc->csel_reg, |
856 | mask: rdev->desc->csel_mask, val: sel); |
857 | } |
858 | EXPORT_SYMBOL_GPL(regulator_set_current_limit_regmap); |
859 | |
860 | /** |
861 | * regulator_get_current_limit_regmap - get_current_limit for regmap users |
862 | * |
863 | * @rdev: regulator to operate on |
864 | * |
865 | * Regulators that use regmap for their register I/O can set the |
866 | * csel_reg and csel_mask fields in their descriptor and then use this |
867 | * as their get_current_limit operation, saving some code. |
868 | */ |
869 | int regulator_get_current_limit_regmap(struct regulator_dev *rdev) |
870 | { |
871 | unsigned int val; |
872 | int ret; |
873 | |
874 | ret = regmap_read(map: rdev->regmap, reg: rdev->desc->csel_reg, val: &val); |
875 | if (ret != 0) |
876 | return ret; |
877 | |
878 | val &= rdev->desc->csel_mask; |
879 | val >>= ffs(rdev->desc->csel_mask) - 1; |
880 | |
881 | if (rdev->desc->curr_table) { |
882 | if (val >= rdev->desc->n_current_limits) |
883 | return -EINVAL; |
884 | |
885 | return rdev->desc->curr_table[val]; |
886 | } |
887 | |
888 | return -EINVAL; |
889 | } |
890 | EXPORT_SYMBOL_GPL(regulator_get_current_limit_regmap); |
891 | |
892 | /** |
893 | * regulator_bulk_set_supply_names - initialize the 'supply' fields in an array |
894 | * of regulator_bulk_data structs |
895 | * |
896 | * @consumers: array of regulator_bulk_data entries to initialize |
897 | * @supply_names: array of supply name strings |
898 | * @num_supplies: number of supply names to initialize |
899 | * |
900 | * Note: the 'consumers' array must be the size of 'num_supplies'. |
901 | */ |
902 | void regulator_bulk_set_supply_names(struct regulator_bulk_data *consumers, |
903 | const char *const *supply_names, |
904 | unsigned int num_supplies) |
905 | { |
906 | unsigned int i; |
907 | |
908 | for (i = 0; i < num_supplies; i++) |
909 | consumers[i].supply = supply_names[i]; |
910 | } |
911 | EXPORT_SYMBOL_GPL(regulator_bulk_set_supply_names); |
912 | |
913 | /** |
914 | * regulator_is_equal - test whether two regulators are the same |
915 | * |
916 | * @reg1: first regulator to operate on |
917 | * @reg2: second regulator to operate on |
918 | */ |
919 | bool regulator_is_equal(struct regulator *reg1, struct regulator *reg2) |
920 | { |
921 | return reg1->rdev == reg2->rdev; |
922 | } |
923 | EXPORT_SYMBOL_GPL(regulator_is_equal); |
924 | |
925 | /** |
926 | * regulator_find_closest_bigger - helper to find offset in ramp delay table |
927 | * |
928 | * @target: targeted ramp_delay |
929 | * @table: table with supported ramp delays |
930 | * @num_sel: number of entries in the table |
931 | * @sel: Pointer to store table offset |
932 | * |
933 | * This is the internal helper used by regulator_set_ramp_delay_regmap to |
934 | * map ramp delay to register value. It should only be used directly if |
935 | * regulator_set_ramp_delay_regmap cannot handle a specific device setup |
936 | * (e.g. because the value is split over multiple registers). |
937 | */ |
938 | int regulator_find_closest_bigger(unsigned int target, const unsigned int *table, |
939 | unsigned int num_sel, unsigned int *sel) |
940 | { |
941 | unsigned int s, tmp, max, maxsel = 0; |
942 | bool found = false; |
943 | |
944 | max = table[0]; |
945 | |
946 | for (s = 0; s < num_sel; s++) { |
947 | if (table[s] > max) { |
948 | max = table[s]; |
949 | maxsel = s; |
950 | } |
951 | if (table[s] >= target) { |
952 | if (!found || table[s] - target < tmp - target) { |
953 | tmp = table[s]; |
954 | *sel = s; |
955 | found = true; |
956 | if (tmp == target) |
957 | break; |
958 | } |
959 | } |
960 | } |
961 | |
962 | if (!found) { |
963 | *sel = maxsel; |
964 | return -EINVAL; |
965 | } |
966 | |
967 | return 0; |
968 | } |
969 | EXPORT_SYMBOL_GPL(regulator_find_closest_bigger); |
970 | |
971 | /** |
972 | * regulator_set_ramp_delay_regmap - set_ramp_delay() helper |
973 | * |
974 | * @rdev: regulator to operate on |
975 | * @ramp_delay: ramp-rate value given in units V/S (uV/uS) |
976 | * |
977 | * Regulators that use regmap for their register I/O can set the ramp_reg |
978 | * and ramp_mask fields in their descriptor and then use this as their |
979 | * set_ramp_delay operation, saving some code. |
980 | */ |
981 | int regulator_set_ramp_delay_regmap(struct regulator_dev *rdev, int ramp_delay) |
982 | { |
983 | int ret; |
984 | unsigned int sel; |
985 | |
986 | if (WARN_ON(!rdev->desc->n_ramp_values || !rdev->desc->ramp_delay_table)) |
987 | return -EINVAL; |
988 | |
989 | ret = regulator_find_closest_bigger(ramp_delay, rdev->desc->ramp_delay_table, |
990 | rdev->desc->n_ramp_values, &sel); |
991 | |
992 | if (ret) { |
993 | dev_warn(rdev_get_dev(rdev), |
994 | "Can't set ramp-delay %u, setting %u\n", ramp_delay, |
995 | rdev->desc->ramp_delay_table[sel]); |
996 | } |
997 | |
998 | sel <<= ffs(rdev->desc->ramp_mask) - 1; |
999 | |
1000 | return regmap_update_bits(map: rdev->regmap, reg: rdev->desc->ramp_reg, |
1001 | mask: rdev->desc->ramp_mask, val: sel); |
1002 | } |
1003 | EXPORT_SYMBOL_GPL(regulator_set_ramp_delay_regmap); |
1004 |
Definitions
- regulator_is_enabled_regmap
- regulator_enable_regmap
- regulator_disable_regmap
- regulator_range_selector_to_index
- regulator_get_voltage_sel_pickable_regmap
- write_separate_vsel_and_range
- regulator_set_voltage_sel_pickable_regmap
- regulator_get_voltage_sel_regmap
- regulator_set_voltage_sel_regmap
- regulator_map_voltage_iterate
- regulator_map_voltage_ascend
- regulator_map_voltage_linear
- regulator_map_voltage_linear_range
- regulator_map_voltage_pickable_linear_range
- regulator_desc_list_voltage_linear
- regulator_list_voltage_linear
- regulator_list_voltage_pickable_linear_range
- regulator_desc_list_voltage_linear_range
- regulator_list_voltage_linear_range
- regulator_list_voltage_table
- regulator_set_bypass_regmap
- regulator_set_soft_start_regmap
- regulator_set_pull_down_regmap
- regulator_get_bypass_regmap
- regulator_set_active_discharge_regmap
- regulator_set_current_limit_regmap
- regulator_get_current_limit_regmap
- regulator_bulk_set_supply_names
- regulator_is_equal
- regulator_find_closest_bigger
Improve your Profiling and Debugging skills
Find out more