regulator: Add helpers for low-level register access
Add helper functions that allow regulator consumers to obtain low-level details about the regulator hardware, like the voltage selector register address and such. These details can be useful when configuring hardware or firmware that want to do low-level access to regulators, with no involvement from the kernel. The use-case for Tegra is a voltage-controlled oscillator clocksource which has control logic to change the supply voltage via I2C to achieve a desired output clock rate. Signed-off-by: Tuomas Tynkkynen <ttynkkynen@nvidia.com> Signed-off-by: Mark Brown <broonie@linaro.org>
This commit is contained in:
parent
7171511eae
commit
04eca28cde
|
@ -180,3 +180,38 @@ int regulator_unregister_notifier(struct regulator *regulator,
|
|||
|
||||
Regulators use the kernel notifier framework to send event to their interested
|
||||
consumers.
|
||||
|
||||
7. Regulator Direct Register Access
|
||||
===================================
|
||||
Some kinds of power management hardware or firmware are designed such that
|
||||
they need to do low-level hardware access to regulators, with no involvement
|
||||
from the kernel. Examples of such devices are:
|
||||
|
||||
- clocksource with a voltage-controlled oscillator and control logic to change
|
||||
the supply voltage over I2C to achieve a desired output clock rate
|
||||
- thermal management firmware that can issue an arbitrary I2C transaction to
|
||||
perform system poweroff during overtemperature conditions
|
||||
|
||||
To set up such a device/firmware, various parameters like I2C address of the
|
||||
regulator, addresses of various regulator registers etc. need to be configured
|
||||
to it. The regulator framework provides the following helpers for querying
|
||||
these details.
|
||||
|
||||
Bus-specific details, like I2C addresses or transfer rates are handled by the
|
||||
regmap framework. To get the regulator's regmap (if supported), use :-
|
||||
|
||||
struct regmap *regulator_get_regmap(struct regulator *regulator);
|
||||
|
||||
To obtain the hardware register offset and bitmask for the regulator's voltage
|
||||
selector register, use :-
|
||||
|
||||
int regulator_get_hardware_vsel_register(struct regulator *regulator,
|
||||
unsigned *vsel_reg,
|
||||
unsigned *vsel_mask);
|
||||
|
||||
To convert a regulator framework voltage selector code (used by
|
||||
regulator_list_voltage) to a hardware-specific voltage selector that can be
|
||||
directly written to the voltage selector register, use :-
|
||||
|
||||
int regulator_list_hardware_vsel(struct regulator *regulator,
|
||||
unsigned selector);
|
||||
|
|
|
@ -2221,6 +2221,77 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_list_voltage);
|
||||
|
||||
/**
|
||||
* regulator_get_regmap - get the regulator's register map
|
||||
* @regulator: regulator source
|
||||
*
|
||||
* Returns the register map for the given regulator, or an ERR_PTR value
|
||||
* if the regulator doesn't use regmap.
|
||||
*/
|
||||
struct regmap *regulator_get_regmap(struct regulator *regulator)
|
||||
{
|
||||
struct regmap *map = regulator->rdev->regmap;
|
||||
|
||||
return map ? map : ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
/**
|
||||
* regulator_get_hardware_vsel_register - get the HW voltage selector register
|
||||
* @regulator: regulator source
|
||||
* @vsel_reg: voltage selector register, output parameter
|
||||
* @vsel_mask: mask for voltage selector bitfield, output parameter
|
||||
*
|
||||
* Returns the hardware register offset and bitmask used for setting the
|
||||
* regulator voltage. This might be useful when configuring voltage-scaling
|
||||
* hardware or firmware that can make I2C requests behind the kernel's back,
|
||||
* for example.
|
||||
*
|
||||
* On success, the output parameters @vsel_reg and @vsel_mask are filled in
|
||||
* and 0 is returned, otherwise a negative errno is returned.
|
||||
*/
|
||||
int regulator_get_hardware_vsel_register(struct regulator *regulator,
|
||||
unsigned *vsel_reg,
|
||||
unsigned *vsel_mask)
|
||||
{
|
||||
struct regulator_dev *rdev = regulator->rdev;
|
||||
struct regulator_ops *ops = rdev->desc->ops;
|
||||
|
||||
if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
*vsel_reg = rdev->desc->vsel_reg;
|
||||
*vsel_mask = rdev->desc->vsel_mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_get_hardware_vsel_register);
|
||||
|
||||
/**
|
||||
* regulator_list_hardware_vsel - get the HW-specific register value for a selector
|
||||
* @regulator: regulator source
|
||||
* @selector: identify voltage to list
|
||||
*
|
||||
* Converts the selector to a hardware-specific voltage selector that can be
|
||||
* directly written to the regulator registers. The address of the voltage
|
||||
* register can be determined by calling @regulator_get_hardware_vsel_register.
|
||||
*
|
||||
* On error a negative errno is returned.
|
||||
*/
|
||||
int regulator_list_hardware_vsel(struct regulator *regulator,
|
||||
unsigned selector)
|
||||
{
|
||||
struct regulator_dev *rdev = regulator->rdev;
|
||||
struct regulator_ops *ops = rdev->desc->ops;
|
||||
|
||||
if (selector >= rdev->desc->n_voltages)
|
||||
return -EINVAL;
|
||||
if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return selector;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_list_hardware_vsel);
|
||||
|
||||
/**
|
||||
* regulator_get_linear_step - return the voltage step size between VSEL values
|
||||
* @regulator: regulator source
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
struct device;
|
||||
struct notifier_block;
|
||||
struct regmap;
|
||||
|
||||
/*
|
||||
* Regulator operating modes.
|
||||
|
@ -215,6 +216,13 @@ int regulator_set_optimum_mode(struct regulator *regulator, int load_uA);
|
|||
|
||||
int regulator_allow_bypass(struct regulator *regulator, bool allow);
|
||||
|
||||
struct regmap *regulator_get_regmap(struct regulator *regulator);
|
||||
int regulator_get_hardware_vsel_register(struct regulator *regulator,
|
||||
unsigned *vsel_reg,
|
||||
unsigned *vsel_mask);
|
||||
int regulator_list_hardware_vsel(struct regulator *regulator,
|
||||
unsigned selector);
|
||||
|
||||
/* regulator notifier block */
|
||||
int regulator_register_notifier(struct regulator *regulator,
|
||||
struct notifier_block *nb);
|
||||
|
@ -452,6 +460,24 @@ static inline int regulator_allow_bypass(struct regulator *regulator,
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct regmap *regulator_get_regmap(struct regulator *regulator)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
int regulator_get_hardware_vsel_register(struct regulator *regulator,
|
||||
unsigned *vsel_reg,
|
||||
unsigned *vsel_mask)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int regulator_list_hardware_vsel(struct regulator *regulator,
|
||||
unsigned selector)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int regulator_register_notifier(struct regulator *regulator,
|
||||
struct notifier_block *nb)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue