aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatti Vaittinen <matti.vaittinen@fi.rohmeurope.com>2018-09-14 04:31:36 -0400
committerMark Brown <broonie@kernel.org>2018-09-28 09:57:03 -0400
commit18e4b55fbd2069cee51ef9660b35c65ec13bee6d (patch)
tree69c0b9d3796c30651bb669bd40cbd81ec9b3ad30
parent01e17e5d8004f53044c6c9062e04ca118c420512 (diff)
regulator: Support regulators where voltage ranges are selectable
For example ROHM BD71837 and ROHM BD71847 Power management ICs have regulators which provide multiple linear ranges. Ranges can be selected by individual non contagious bit in vsel register. Add regmap helper functions for selecting ranges. Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--drivers/regulator/core.c5
-rw-r--r--drivers/regulator/helpers.c232
-rw-r--r--include/linux/regulator/driver.h20
3 files changed, 256 insertions, 1 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 9577d8941846..4b1755a8ef00 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2783,6 +2783,11 @@ static int regulator_map_voltage(struct regulator_dev *rdev, int min_uV,
2783 if (desc->ops->list_voltage == regulator_list_voltage_linear_range) 2783 if (desc->ops->list_voltage == regulator_list_voltage_linear_range)
2784 return regulator_map_voltage_linear_range(rdev, min_uV, max_uV); 2784 return regulator_map_voltage_linear_range(rdev, min_uV, max_uV);
2785 2785
2786 if (desc->ops->list_voltage ==
2787 regulator_list_voltage_pickable_linear_range)
2788 return regulator_map_voltage_pickable_linear_range(rdev,
2789 min_uV, max_uV);
2790
2786 return regulator_map_voltage_iterate(rdev, min_uV, max_uV); 2791 return regulator_map_voltage_iterate(rdev, min_uV, max_uV);
2787} 2792}
2788 2793
diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c
index 2ae7c3ac5940..d2b9fc359318 100644
--- a/drivers/regulator/helpers.c
+++ b/drivers/regulator/helpers.c
@@ -103,6 +103,128 @@ int regulator_disable_regmap(struct regulator_dev *rdev)
103} 103}
104EXPORT_SYMBOL_GPL(regulator_disable_regmap); 104EXPORT_SYMBOL_GPL(regulator_disable_regmap);
105 105
106static int regulator_range_selector_to_index(struct regulator_dev *rdev,
107 unsigned int rval)
108{
109 int i;
110
111 if (!rdev->desc->linear_range_selectors)
112 return -EINVAL;
113
114 rval &= rdev->desc->vsel_range_mask;
115
116 for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
117 if (rdev->desc->linear_range_selectors[i] == rval)
118 return i;
119 }
120 return -EINVAL;
121}
122
123/**
124 * regulator_get_voltage_sel_pickable_regmap - pickable range get_voltage_sel
125 *
126 * @rdev: regulator to operate on
127 *
128 * Regulators that use regmap for their register I/O and use pickable
129 * ranges can set the vsel_reg, vsel_mask, vsel_range_reg and vsel_range_mask
130 * fields in their descriptor and then use this as their get_voltage_vsel
131 * operation, saving some code.
132 */
133int regulator_get_voltage_sel_pickable_regmap(struct regulator_dev *rdev)
134{
135 unsigned int r_val;
136 int range;
137 unsigned int val;
138 int ret, i;
139 unsigned int voltages_in_range = 0;
140
141 if (!rdev->desc->linear_ranges)
142 return -EINVAL;
143
144 ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);
145 if (ret != 0)
146 return ret;
147
148 ret = regmap_read(rdev->regmap, rdev->desc->vsel_range_reg, &r_val);
149 if (ret != 0)
150 return ret;
151
152 val &= rdev->desc->vsel_mask;
153 val >>= ffs(rdev->desc->vsel_mask) - 1;
154
155 range = regulator_range_selector_to_index(rdev, r_val);
156 if (range < 0)
157 return -EINVAL;
158
159 for (i = 0; i < range; i++)
160 voltages_in_range += (rdev->desc->linear_ranges[i].max_sel -
161 rdev->desc->linear_ranges[i].min_sel) + 1;
162
163 return val + voltages_in_range;
164}
165EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_pickable_regmap);
166
167/**
168 * regulator_set_voltage_sel_pickable_regmap - pickable range set_voltage_sel
169 *
170 * @rdev: regulator to operate on
171 * @sel: Selector to set
172 *
173 * Regulators that use regmap for their register I/O and use pickable
174 * ranges can set the vsel_reg, vsel_mask, vsel_range_reg and vsel_range_mask
175 * fields in their descriptor and then use this as their set_voltage_vsel
176 * operation, saving some code.
177 */
178int regulator_set_voltage_sel_pickable_regmap(struct regulator_dev *rdev,
179 unsigned int sel)
180{
181 unsigned int range;
182 int ret, i;
183 unsigned int voltages_in_range = 0;
184
185 for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
186 voltages_in_range = (rdev->desc->linear_ranges[i].max_sel -
187 rdev->desc->linear_ranges[i].min_sel) + 1;
188 if (sel < voltages_in_range)
189 break;
190 sel -= voltages_in_range;
191 }
192
193 if (i == rdev->desc->n_linear_ranges)
194 return -EINVAL;
195
196 sel <<= ffs(rdev->desc->vsel_mask) - 1;
197 sel += rdev->desc->linear_ranges[i].min_sel;
198
199 range = rdev->desc->linear_range_selectors[i];
200
201 if (rdev->desc->vsel_reg == rdev->desc->vsel_range_reg) {
202 ret = regmap_update_bits(rdev->regmap,
203 rdev->desc->vsel_reg,
204 rdev->desc->vsel_range_mask |
205 rdev->desc->vsel_mask, sel | range);
206 } else {
207 ret = regmap_update_bits(rdev->regmap,
208 rdev->desc->vsel_range_reg,
209 rdev->desc->vsel_range_mask, range);
210 if (ret)
211 return ret;
212
213 ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
214 rdev->desc->vsel_mask, sel);
215 }
216
217 if (ret)
218 return ret;
219
220 if (rdev->desc->apply_bit)
221 ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg,
222 rdev->desc->apply_bit,
223 rdev->desc->apply_bit);
224 return ret;
225}
226EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_pickable_regmap);
227
106/** 228/**
107 * regulator_get_voltage_sel_regmap - standard get_voltage_sel for regmap users 229 * regulator_get_voltage_sel_regmap - standard get_voltage_sel for regmap users
108 * 230 *
@@ -337,6 +459,76 @@ int regulator_map_voltage_linear_range(struct regulator_dev *rdev,
337EXPORT_SYMBOL_GPL(regulator_map_voltage_linear_range); 459EXPORT_SYMBOL_GPL(regulator_map_voltage_linear_range);
338 460
339/** 461/**
462 * regulator_map_voltage_pickable_linear_range - map_voltage, pickable ranges
463 *
464 * @rdev: Regulator to operate on
465 * @min_uV: Lower bound for voltage
466 * @max_uV: Upper bound for voltage
467 *
468 * Drivers providing pickable linear_ranges in their descriptor can use
469 * this as their map_voltage() callback.
470 */
471int regulator_map_voltage_pickable_linear_range(struct regulator_dev *rdev,
472 int min_uV, int max_uV)
473{
474 const struct regulator_linear_range *range;
475 int ret = -EINVAL;
476 int voltage, i;
477 unsigned int selector = 0;
478
479 if (!rdev->desc->n_linear_ranges) {
480 BUG_ON(!rdev->desc->n_linear_ranges);
481 return -EINVAL;
482 }
483
484 for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
485 int linear_max_uV;
486
487 range = &rdev->desc->linear_ranges[i];
488 linear_max_uV = range->min_uV +
489 (range->max_sel - range->min_sel) * range->uV_step;
490
491 if (!(min_uV <= linear_max_uV && max_uV >= range->min_uV)) {
492 selector += (range->max_sel - range->min_sel + 1);
493 continue;
494 }
495
496 if (min_uV <= range->min_uV)
497 min_uV = range->min_uV;
498
499 /* range->uV_step == 0 means fixed voltage range */
500 if (range->uV_step == 0) {
501 ret = 0;
502 } else {
503 ret = DIV_ROUND_UP(min_uV - range->min_uV,
504 range->uV_step);
505 if (ret < 0)
506 return ret;
507 }
508
509 ret += selector;
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 += (range->max_sel - range->min_sel + 1);
520 else
521 break;
522 }
523
524 if (i == rdev->desc->n_linear_ranges)
525 return -EINVAL;
526
527 return ret;
528}
529EXPORT_SYMBOL_GPL(regulator_map_voltage_pickable_linear_range);
530
531/**
340 * regulator_list_voltage_linear - List voltages with simple calculation 532 * regulator_list_voltage_linear - List voltages with simple calculation
341 * 533 *
342 * @rdev: Regulator device 534 * @rdev: Regulator device
@@ -361,6 +553,46 @@ int regulator_list_voltage_linear(struct regulator_dev *rdev,
361EXPORT_SYMBOL_GPL(regulator_list_voltage_linear); 553EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
362 554
363/** 555/**
556 * regulator_list_voltage_pickable_linear_range - pickable range list voltages
557 *
558 * @rdev: Regulator device
559 * @selector: Selector to convert into a voltage
560 *
561 * list_voltage() operation, intended to be used by drivers utilizing pickable
562 * ranges helpers.
563 */
564int regulator_list_voltage_pickable_linear_range(struct regulator_dev *rdev,
565 unsigned int selector)
566{
567 const struct regulator_linear_range *range;
568 int i;
569 unsigned int all_sels = 0;
570
571 if (!rdev->desc->n_linear_ranges) {
572 BUG_ON(!rdev->desc->n_linear_ranges);
573 return -EINVAL;
574 }
575
576 for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
577 unsigned int sels_in_range;
578
579 range = &rdev->desc->linear_ranges[i];
580
581 sels_in_range = range->max_sel - range->min_sel;
582
583 if (all_sels + sels_in_range >= selector) {
584 selector -= all_sels;
585 return range->min_uV + (range->uV_step * selector);
586 }
587
588 all_sels += (sels_in_range + 1);
589 }
590
591 return -EINVAL;
592}
593EXPORT_SYMBOL_GPL(regulator_list_voltage_pickable_linear_range);
594
595/**
364 * regulator_list_voltage_linear_range - List voltages for linear ranges 596 * regulator_list_voltage_linear_range - List voltages for linear ranges
365 * 597 *
366 * @rdev: Regulator device 598 * @rdev: Regulator device
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 0fd8fbb74763..a9c030192147 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -271,9 +271,16 @@ enum regulator_type {
271 * @ramp_delay: Time to settle down after voltage change (unit: uV/us) 271 * @ramp_delay: Time to settle down after voltage change (unit: uV/us)
272 * @min_dropout_uV: The minimum dropout voltage this regulator can handle 272 * @min_dropout_uV: The minimum dropout voltage this regulator can handle
273 * @linear_ranges: A constant table of possible voltage ranges. 273 * @linear_ranges: A constant table of possible voltage ranges.
274 * @n_linear_ranges: Number of entries in the @linear_ranges table. 274 * @linear_range_selectors: A constant table of voltage range selectors.
275 * If pickable ranges are used each range must
276 * have corresponding selector here.
277 * @n_linear_ranges: Number of entries in the @linear_ranges (and in
278 * linear_range_selectors if used) table(s).
275 * @volt_table: Voltage mapping table (if table based mapping) 279 * @volt_table: Voltage mapping table (if table based mapping)
276 * 280 *
281 * @vsel_range_reg: Register for range selector when using pickable ranges
282 * and regulator_regmap_X_voltage_X_pickable functions.
283 * @vsel_range_mask: Mask for register bitfield used for range selector
277 * @vsel_reg: Register for selector when using regulator_regmap_X_voltage_ 284 * @vsel_reg: Register for selector when using regulator_regmap_X_voltage_
278 * @vsel_mask: Mask for register bitfield used for selector 285 * @vsel_mask: Mask for register bitfield used for selector
279 * @csel_reg: Register for TPS65218 LS3 current regulator 286 * @csel_reg: Register for TPS65218 LS3 current regulator
@@ -338,10 +345,14 @@ struct regulator_desc {
338 int min_dropout_uV; 345 int min_dropout_uV;
339 346
340 const struct regulator_linear_range *linear_ranges; 347 const struct regulator_linear_range *linear_ranges;
348 const unsigned int *linear_range_selectors;
349
341 int n_linear_ranges; 350 int n_linear_ranges;
342 351
343 const unsigned int *volt_table; 352 const unsigned int *volt_table;
344 353
354 unsigned int vsel_range_reg;
355 unsigned int vsel_range_mask;
345 unsigned int vsel_reg; 356 unsigned int vsel_reg;
346 unsigned int vsel_mask; 357 unsigned int vsel_mask;
347 unsigned int csel_reg; 358 unsigned int csel_reg;
@@ -498,18 +509,25 @@ int regulator_mode_to_status(unsigned int);
498 509
499int regulator_list_voltage_linear(struct regulator_dev *rdev, 510int regulator_list_voltage_linear(struct regulator_dev *rdev,
500 unsigned int selector); 511 unsigned int selector);
512int regulator_list_voltage_pickable_linear_range(struct regulator_dev *rdev,
513 unsigned int selector);
501int regulator_list_voltage_linear_range(struct regulator_dev *rdev, 514int regulator_list_voltage_linear_range(struct regulator_dev *rdev,
502 unsigned int selector); 515 unsigned int selector);
503int regulator_list_voltage_table(struct regulator_dev *rdev, 516int regulator_list_voltage_table(struct regulator_dev *rdev,
504 unsigned int selector); 517 unsigned int selector);
505int regulator_map_voltage_linear(struct regulator_dev *rdev, 518int regulator_map_voltage_linear(struct regulator_dev *rdev,
506 int min_uV, int max_uV); 519 int min_uV, int max_uV);
520int regulator_map_voltage_pickable_linear_range(struct regulator_dev *rdev,
521 int min_uV, int max_uV);
507int regulator_map_voltage_linear_range(struct regulator_dev *rdev, 522int regulator_map_voltage_linear_range(struct regulator_dev *rdev,
508 int min_uV, int max_uV); 523 int min_uV, int max_uV);
509int regulator_map_voltage_iterate(struct regulator_dev *rdev, 524int regulator_map_voltage_iterate(struct regulator_dev *rdev,
510 int min_uV, int max_uV); 525 int min_uV, int max_uV);
511int regulator_map_voltage_ascend(struct regulator_dev *rdev, 526int regulator_map_voltage_ascend(struct regulator_dev *rdev,
512 int min_uV, int max_uV); 527 int min_uV, int max_uV);
528int regulator_get_voltage_sel_pickable_regmap(struct regulator_dev *rdev);
529int regulator_set_voltage_sel_pickable_regmap(struct regulator_dev *rdev,
530 unsigned int sel);
513int regulator_get_voltage_sel_regmap(struct regulator_dev *rdev); 531int regulator_get_voltage_sel_regmap(struct regulator_dev *rdev);
514int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel); 532int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel);
515int regulator_is_enabled_regmap(struct regulator_dev *rdev); 533int regulator_is_enabled_regmap(struct regulator_dev *rdev);