Skip to content

Commit

Permalink
regulator: core: Add helpers for multiple linear ranges
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Mark Brown committed Jul 15, 2013
1 parent ad81f05 commit 94d33c0
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 0 deletions.
87 changes: 87 additions & 0 deletions drivers/regulator/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -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)
{
Expand Down
25 changes: 25 additions & 0 deletions include/linux/regulator/driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 94d33c0

Please sign in to comment.