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
@ -2078,6 +2078,43 @@ int regulator_list_voltage_linear(struct regulator_dev *rdev,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
|
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
|
* 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);
|
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,
|
static int _regulator_do_set_voltage(struct regulator_dev *rdev,
|
||||||
int min_uV, int max_uV)
|
int min_uV, int max_uV)
|
||||||
{
|
{
|
||||||
|
@ -39,6 +39,24 @@ enum regulator_status {
|
|||||||
REGULATOR_STATUS_UNDEFINED,
|
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.
|
* struct regulator_ops - regulator operations.
|
||||||
*
|
*
|
||||||
@ -223,6 +241,9 @@ struct regulator_desc {
|
|||||||
unsigned int linear_min_sel;
|
unsigned int linear_min_sel;
|
||||||
unsigned int ramp_delay;
|
unsigned int ramp_delay;
|
||||||
|
|
||||||
|
const struct regulator_linear_range *linear_ranges;
|
||||||
|
int n_linear_ranges;
|
||||||
|
|
||||||
const unsigned int *volt_table;
|
const unsigned int *volt_table;
|
||||||
|
|
||||||
unsigned int vsel_reg;
|
unsigned int vsel_reg;
|
||||||
@ -326,10 +347,14 @@ int regulator_mode_to_status(unsigned int);
|
|||||||
|
|
||||||
int regulator_list_voltage_linear(struct regulator_dev *rdev,
|
int regulator_list_voltage_linear(struct regulator_dev *rdev,
|
||||||
unsigned int selector);
|
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,
|
int regulator_list_voltage_table(struct regulator_dev *rdev,
|
||||||
unsigned int selector);
|
unsigned int selector);
|
||||||
int regulator_map_voltage_linear(struct regulator_dev *rdev,
|
int regulator_map_voltage_linear(struct regulator_dev *rdev,
|
||||||
int min_uV, int max_uV);
|
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 regulator_map_voltage_iterate(struct regulator_dev *rdev,
|
||||||
int min_uV, int max_uV);
|
int min_uV, int max_uV);
|
||||||
int regulator_map_voltage_ascend(struct regulator_dev *rdev,
|
int regulator_map_voltage_ascend(struct regulator_dev *rdev,
|
||||||
|
Loading…
Reference in New Issue
Block a user