mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-06 10:57:46 +00:00
regulator: core: Add helpers for multiple linear ranges
Many regulators have several linear ranges of selector with different step sizes, for example offering better resolution at lower voltages. Provide regulator_{map,list}_voltage_linear_range() allowing these regulators to use generic code. To do so a table of regulator_linear_range structs needs to be pointed to from the descriptor. This was inspired by similar code included in a driver submission from Chao Xie and Yi Zhang at Marvell. Signed-off-by: Mark Brown <broonie@linaro.org>
This commit is contained in:
parent
ad81f0545e
commit
94d33c02c7
2 changed files with 112 additions and 0 deletions
|
@ -2078,6 +2078,43 @@ int regulator_list_voltage_linear(struct regulator_dev *rdev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
|
||||
|
||||
/**
|
||||
* regulator_list_voltage_linear_range - List voltages for linear ranges
|
||||
*
|
||||
* @rdev: Regulator device
|
||||
* @selector: Selector to convert into a voltage
|
||||
*
|
||||
* Regulators with a series of simple linear mappings between voltages
|
||||
* and selectors can set linear_ranges in the regulator descriptor and
|
||||
* then use this function as their list_voltage() operation,
|
||||
*/
|
||||
int regulator_list_voltage_linear_range(struct regulator_dev *rdev,
|
||||
unsigned int selector)
|
||||
{
|
||||
const struct regulator_linear_range *range;
|
||||
int i;
|
||||
|
||||
if (!rdev->desc->n_linear_ranges) {
|
||||
BUG_ON(!rdev->desc->n_linear_ranges);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
|
||||
range = &rdev->desc->linear_ranges[i];
|
||||
|
||||
if (!(selector >= range->min_sel &&
|
||||
selector <= range->max_sel))
|
||||
continue;
|
||||
|
||||
selector -= range->min_sel;
|
||||
|
||||
return range->min_uV + (range->uV_step * selector);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_list_voltage_linear_range);
|
||||
|
||||
/**
|
||||
* regulator_list_voltage_table - List voltages with table based mapping
|
||||
*
|
||||
|
@ -2368,6 +2405,56 @@ int regulator_map_voltage_linear(struct regulator_dev *rdev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_map_voltage_linear);
|
||||
|
||||
/**
|
||||
* regulator_map_voltage_linear - map_voltage() for multiple linear ranges
|
||||
*
|
||||
* @rdev: Regulator to operate on
|
||||
* @min_uV: Lower bound for voltage
|
||||
* @max_uV: Upper bound for voltage
|
||||
*
|
||||
* Drivers providing linear_ranges in their descriptor can use this as
|
||||
* their map_voltage() callback.
|
||||
*/
|
||||
int regulator_map_voltage_linear_range(struct regulator_dev *rdev,
|
||||
int min_uV, int max_uV)
|
||||
{
|
||||
const struct regulator_linear_range *range;
|
||||
int ret = -EINVAL;
|
||||
int voltage, i;
|
||||
|
||||
if (!rdev->desc->n_linear_ranges) {
|
||||
BUG_ON(!rdev->desc->n_linear_ranges);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
|
||||
range = &rdev->desc->linear_ranges[i];
|
||||
|
||||
if (!(min_uV <= range->max_uV && max_uV >= range->min_uV))
|
||||
continue;
|
||||
|
||||
if (min_uV <= range->min_uV)
|
||||
min_uV = range->min_uV;
|
||||
|
||||
ret = DIV_ROUND_UP(min_uV - range->min_uV, range->uV_step);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == rdev->desc->n_linear_ranges)
|
||||
return -EINVAL;
|
||||
|
||||
/* Map back into a voltage to verify we're still in bounds */
|
||||
voltage = rdev->desc->ops->list_voltage(rdev, ret);
|
||||
if (voltage < min_uV || voltage > max_uV)
|
||||
return -EINVAL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_map_voltage_linear_range);
|
||||
|
||||
static int _regulator_do_set_voltage(struct regulator_dev *rdev,
|
||||
int min_uV, int max_uV)
|
||||
{
|
||||
|
|
|
@ -39,6 +39,24 @@ enum regulator_status {
|
|||
REGULATOR_STATUS_UNDEFINED,
|
||||
};
|
||||
|
||||
/**
|
||||
* Specify a range of voltages for regulator_map_linar_range() and
|
||||
* regulator_list_linear_range().
|
||||
*
|
||||
* @min_uV: Lowest voltage in range
|
||||
* @max_uV: Highest voltage in range
|
||||
* @min_sel: Lowest selector for range
|
||||
* @max_sel: Highest selector for range
|
||||
* @uV_step: Step size
|
||||
*/
|
||||
struct regulator_linear_range {
|
||||
unsigned int min_uV;
|
||||
unsigned int max_uV;
|
||||
unsigned int min_sel;
|
||||
unsigned int max_sel;
|
||||
unsigned int uV_step;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct regulator_ops - regulator operations.
|
||||
*
|
||||
|
@ -223,6 +241,9 @@ struct regulator_desc {
|
|||
unsigned int linear_min_sel;
|
||||
unsigned int ramp_delay;
|
||||
|
||||
const struct regulator_linear_range *linear_ranges;
|
||||
int n_linear_ranges;
|
||||
|
||||
const unsigned int *volt_table;
|
||||
|
||||
unsigned int vsel_reg;
|
||||
|
@ -326,10 +347,14 @@ int regulator_mode_to_status(unsigned int);
|
|||
|
||||
int regulator_list_voltage_linear(struct regulator_dev *rdev,
|
||||
unsigned int selector);
|
||||
int regulator_list_voltage_linear_range(struct regulator_dev *rdev,
|
||||
unsigned int selector);
|
||||
int regulator_list_voltage_table(struct regulator_dev *rdev,
|
||||
unsigned int selector);
|
||||
int regulator_map_voltage_linear(struct regulator_dev *rdev,
|
||||
int min_uV, int max_uV);
|
||||
int regulator_map_voltage_linear_range(struct regulator_dev *rdev,
|
||||
int min_uV, int max_uV);
|
||||
int regulator_map_voltage_iterate(struct regulator_dev *rdev,
|
||||
int min_uV, int max_uV);
|
||||
int regulator_map_voltage_ascend(struct regulator_dev *rdev,
|
||||
|
|
Loading…
Reference in a new issue