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:
Mark Brown 2013-07-02 22:52:41 +01:00
parent ad81f0545e
commit 94d33c02c7
2 changed files with 112 additions and 0 deletions

View File

@ -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)
{

View File

@ -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,