regulator: Bypass mode support
Allow regulators to be put into a non-regulating mode bypassing the input straight to the output, mostly used by low power retention modes. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJQYuORAAoJEOoSHmUN5Tg4xRUQAL1OwYJsLfbwNEjeVnxDjpWU La4HS3xLYZ/CHHSXJRJnithc/fqrjuTryEMUYVDaXW3MHt53Yc98ENJmnieurR4Y LJ6lMI2+DKPmgiR9G2HlqOUPbqBRMytAQS7e8u+xLV4MFB+xSPO/y/ntHPfQCzS3 OqEU1xXkmxRMUPBugY5fgoI92tpYAmTJwP+EziiBV5mWjL85DA7oARGU1V3opgrh EKJzMFdiajtCaTj8JTjMDaGLAd6+R8S1TrT+dEF85VWZgVCcMG+RY37z3oknWfHR 2yDC7jBRl9LiPaP/QvBegbauU862uQlZo0Kz3xDPdU3a1fV7ugpuIusuQCalh0nD RHLaiqK4Y8xDvvh0P6WwBKY1HTTs6Y0vgN/OqYoLETnavkOV8LM4JnkoHb9BfeiP LhGKBX5u/AiffDL30gVhy5adSXLJQBPyFYjVXCXZQB6EA4XsDxS+bVq31E0XXCY+ JsNOOu391sEsOPrtpnGDsztvG+AMKBWDe594xGUTWJKnlScW3vd3wEWS1JNw90TG TkiA6GadKRADPV1R49iEJdKRcgqGnbY3+msP3rK9Pe/0gxF4QSfSwmvE9eWv+UFA Jq0899StOIbovIC+IyY49CgxiewnwOeZO52dmU4gQ7EiXzq4y2wsGYX4SMd52B2q dqTs4BzNw2B/kcrPw3Qb =Fi2j -----END PGP SIGNATURE----- Merge tag 'bypass' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator into for-3.7 regulator: Bypass mode support Allow regulators to be put into a non-regulating mode bypassing the input straight to the output, mostly used by low power retention modes.
This commit is contained in:
commit
8f6862d4bd
|
@ -349,3 +349,24 @@ Description:
|
|||
|
||||
This will be one of the same strings reported by
|
||||
the "state" attribute.
|
||||
|
||||
What: /sys/class/regulator/.../bypass
|
||||
Date: September 2012
|
||||
KernelVersion: 3.7
|
||||
Contact: Mark Brown <broonie@opensource.wolfsonmicro.com>
|
||||
Description:
|
||||
Some regulator directories will contain a field called
|
||||
bypass. This indicates if the device is in bypass mode.
|
||||
|
||||
This will be one of the following strings:
|
||||
|
||||
'enabled'
|
||||
'disabled'
|
||||
'unknown'
|
||||
|
||||
'enabled' means the regulator is in bypass mode.
|
||||
|
||||
'disabled' means that the regulator is regulating.
|
||||
|
||||
'unknown' means software cannot determine the state, or
|
||||
the reported state is invalid.
|
||||
|
|
|
@ -434,6 +434,11 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev)
|
|||
regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
|
||||
ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
|
||||
|
||||
ret = regulator_allow_bypass(info->micvdd, true);
|
||||
if (ret != 0)
|
||||
dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
|
||||
ret);
|
||||
|
||||
pm_runtime_put(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -39,6 +39,8 @@ static struct regulator_ops arizona_ldo1_ops = {
|
|||
.map_voltage = regulator_map_voltage_linear,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.get_bypass = regulator_get_bypass_regmap,
|
||||
.set_bypass = regulator_set_bypass_regmap,
|
||||
};
|
||||
|
||||
static const struct regulator_desc arizona_ldo1 = {
|
||||
|
@ -49,6 +51,8 @@ static const struct regulator_desc arizona_ldo1 = {
|
|||
|
||||
.vsel_reg = ARIZONA_LDO1_CONTROL_1,
|
||||
.vsel_mask = ARIZONA_LDO1_VSEL_MASK,
|
||||
.bypass_reg = ARIZONA_LDO1_CONTROL_1,
|
||||
.bypass_mask = ARIZONA_LDO1_BYPASS,
|
||||
.min_uV = 900000,
|
||||
.uV_step = 50000,
|
||||
.n_voltages = 7,
|
||||
|
|
|
@ -82,6 +82,9 @@ static struct regulator_ops arizona_micsupp_ops = {
|
|||
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
|
||||
.get_bypass = regulator_get_bypass_regmap,
|
||||
.set_bypass = regulator_set_bypass_regmap,
|
||||
};
|
||||
|
||||
static const struct regulator_desc arizona_micsupp = {
|
||||
|
@ -95,6 +98,8 @@ static const struct regulator_desc arizona_micsupp = {
|
|||
.vsel_mask = ARIZONA_LDO2_VSEL_MASK,
|
||||
.enable_reg = ARIZONA_MIC_CHARGE_PUMP_1,
|
||||
.enable_mask = ARIZONA_CPMIC_ENA,
|
||||
.bypass_reg = ARIZONA_MIC_CHARGE_PUMP_1,
|
||||
.bypass_mask = ARIZONA_CPMIC_BYPASS,
|
||||
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
|
|
@ -77,6 +77,7 @@ struct regulator {
|
|||
struct device *dev;
|
||||
struct list_head list;
|
||||
unsigned int always_on:1;
|
||||
unsigned int bypass:1;
|
||||
int uA_load;
|
||||
int min_uV;
|
||||
int max_uV;
|
||||
|
@ -394,6 +395,9 @@ static ssize_t regulator_status_show(struct device *dev,
|
|||
case REGULATOR_STATUS_STANDBY:
|
||||
label = "standby";
|
||||
break;
|
||||
case REGULATOR_STATUS_BYPASS:
|
||||
label = "bypass";
|
||||
break;
|
||||
case REGULATOR_STATUS_UNDEFINED:
|
||||
label = "undefined";
|
||||
break;
|
||||
|
@ -585,6 +589,27 @@ static ssize_t regulator_suspend_standby_state_show(struct device *dev,
|
|||
static DEVICE_ATTR(suspend_standby_state, 0444,
|
||||
regulator_suspend_standby_state_show, NULL);
|
||||
|
||||
static ssize_t regulator_bypass_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct regulator_dev *rdev = dev_get_drvdata(dev);
|
||||
const char *report;
|
||||
bool bypass;
|
||||
int ret;
|
||||
|
||||
ret = rdev->desc->ops->get_bypass(rdev, &bypass);
|
||||
|
||||
if (ret != 0)
|
||||
report = "unknown";
|
||||
else if (bypass)
|
||||
report = "enabled";
|
||||
else
|
||||
report = "disabled";
|
||||
|
||||
return sprintf(buf, "%s\n", report);
|
||||
}
|
||||
static DEVICE_ATTR(bypass, 0444,
|
||||
regulator_bypass_show, NULL);
|
||||
|
||||
/*
|
||||
* These are the only attributes are present for all regulators.
|
||||
|
@ -2673,6 +2698,100 @@ out:
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_set_optimum_mode);
|
||||
|
||||
/**
|
||||
* regulator_set_bypass_regmap - Default set_bypass() using regmap
|
||||
*
|
||||
* @rdev: device to operate on.
|
||||
* @enable: state to set.
|
||||
*/
|
||||
int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
if (enable)
|
||||
val = rdev->desc->bypass_mask;
|
||||
else
|
||||
val = 0;
|
||||
|
||||
return regmap_update_bits(rdev->regmap, rdev->desc->bypass_reg,
|
||||
rdev->desc->bypass_mask, val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_set_bypass_regmap);
|
||||
|
||||
/**
|
||||
* regulator_get_bypass_regmap - Default get_bypass() using regmap
|
||||
*
|
||||
* @rdev: device to operate on.
|
||||
* @enable: current state.
|
||||
*/
|
||||
int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable)
|
||||
{
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(rdev->regmap, rdev->desc->bypass_reg, &val);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
*enable = val & rdev->desc->bypass_mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_get_bypass_regmap);
|
||||
|
||||
/**
|
||||
* regulator_allow_bypass - allow the regulator to go into bypass mode
|
||||
*
|
||||
* @regulator: Regulator to configure
|
||||
* @allow: enable or disable bypass mode
|
||||
*
|
||||
* Allow the regulator to go into bypass mode if all other consumers
|
||||
* for the regulator also enable bypass mode and the machine
|
||||
* constraints allow this. Bypass mode means that the regulator is
|
||||
* simply passing the input directly to the output with no regulation.
|
||||
*/
|
||||
int regulator_allow_bypass(struct regulator *regulator, bool enable)
|
||||
{
|
||||
struct regulator_dev *rdev = regulator->rdev;
|
||||
int ret = 0;
|
||||
|
||||
if (!rdev->desc->ops->set_bypass)
|
||||
return 0;
|
||||
|
||||
if (rdev->constraints &&
|
||||
!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_BYPASS))
|
||||
return 0;
|
||||
|
||||
mutex_lock(&rdev->mutex);
|
||||
|
||||
if (enable && !regulator->bypass) {
|
||||
rdev->bypass_count++;
|
||||
|
||||
if (rdev->bypass_count == rdev->open_count) {
|
||||
ret = rdev->desc->ops->set_bypass(rdev, enable);
|
||||
if (ret != 0)
|
||||
rdev->bypass_count--;
|
||||
}
|
||||
|
||||
} else if (!enable && regulator->bypass) {
|
||||
rdev->bypass_count--;
|
||||
|
||||
if (rdev->bypass_count != rdev->open_count) {
|
||||
ret = rdev->desc->ops->set_bypass(rdev, enable);
|
||||
if (ret != 0)
|
||||
rdev->bypass_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
regulator->bypass = enable;
|
||||
|
||||
mutex_unlock(&rdev->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_allow_bypass);
|
||||
|
||||
/**
|
||||
* regulator_register_notifier - register regulator event notifier
|
||||
* @regulator: regulator source
|
||||
|
@ -3036,6 +3155,11 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
|
|||
if (status < 0)
|
||||
return status;
|
||||
}
|
||||
if (ops->get_bypass) {
|
||||
status = device_create_file(dev, &dev_attr_bypass);
|
||||
if (status < 0)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* some attributes are type-specific */
|
||||
if (rdev->desc->type == REGULATOR_CURRENT) {
|
||||
|
@ -3124,6 +3248,8 @@ static void rdev_init_debugfs(struct regulator_dev *rdev)
|
|||
&rdev->use_count);
|
||||
debugfs_create_u32("open_count", 0444, rdev->debugfs,
|
||||
&rdev->open_count);
|
||||
debugfs_create_u32("bypass_count", 0444, rdev->debugfs,
|
||||
&rdev->bypass_count);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -237,6 +237,8 @@ static struct regulator_ops wm831x_gp_ldo_ops = {
|
|||
.set_mode = wm831x_gp_ldo_set_mode,
|
||||
.get_status = wm831x_gp_ldo_get_status,
|
||||
.get_optimum_mode = wm831x_gp_ldo_get_optimum_mode,
|
||||
.get_bypass = regulator_get_bypass_regmap,
|
||||
.set_bypass = regulator_set_bypass_regmap,
|
||||
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.enable = regulator_enable_regmap,
|
||||
|
@ -293,6 +295,8 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev)
|
|||
ldo->desc.vsel_mask = WM831X_LDO1_ON_VSEL_MASK;
|
||||
ldo->desc.enable_reg = WM831X_LDO_ENABLE;
|
||||
ldo->desc.enable_mask = 1 << id;
|
||||
ldo->desc.bypass_reg = ldo->base;
|
||||
ldo->desc.bypass_mask = WM831X_LDO1_SWI;
|
||||
|
||||
config.dev = pdev->dev.parent;
|
||||
if (pdata)
|
||||
|
@ -488,6 +492,8 @@ static struct regulator_ops wm831x_aldo_ops = {
|
|||
.get_mode = wm831x_aldo_get_mode,
|
||||
.set_mode = wm831x_aldo_set_mode,
|
||||
.get_status = wm831x_aldo_get_status,
|
||||
.set_bypass = regulator_set_bypass_regmap,
|
||||
.get_bypass = regulator_get_bypass_regmap,
|
||||
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.enable = regulator_enable_regmap,
|
||||
|
@ -544,6 +550,8 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev)
|
|||
ldo->desc.vsel_mask = WM831X_LDO7_ON_VSEL_MASK;
|
||||
ldo->desc.enable_reg = WM831X_LDO_ENABLE;
|
||||
ldo->desc.enable_mask = 1 << id;
|
||||
ldo->desc.bypass_reg = ldo->base;
|
||||
ldo->desc.bypass_mask = WM831X_LDO7_SWI;
|
||||
|
||||
config.dev = pdev->dev.parent;
|
||||
if (pdata)
|
||||
|
|
|
@ -177,6 +177,8 @@ int regulator_set_mode(struct regulator *regulator, unsigned int mode);
|
|||
unsigned int regulator_get_mode(struct regulator *regulator);
|
||||
int regulator_set_optimum_mode(struct regulator *regulator, int load_uA);
|
||||
|
||||
int regulator_allow_bypass(struct regulator *regulator, bool allow);
|
||||
|
||||
/* regulator notifier block */
|
||||
int regulator_register_notifier(struct regulator *regulator,
|
||||
struct notifier_block *nb);
|
||||
|
@ -328,6 +330,12 @@ static inline int regulator_set_optimum_mode(struct regulator *regulator,
|
|||
return REGULATOR_MODE_NORMAL;
|
||||
}
|
||||
|
||||
static inline int regulator_allow_bypass(struct regulator *regulator,
|
||||
bool allow)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int regulator_register_notifier(struct regulator *regulator,
|
||||
struct notifier_block *nb)
|
||||
{
|
||||
|
|
|
@ -32,6 +32,8 @@ enum regulator_status {
|
|||
REGULATOR_STATUS_NORMAL,
|
||||
REGULATOR_STATUS_IDLE,
|
||||
REGULATOR_STATUS_STANDBY,
|
||||
/* The regulator is enabled but not regulating */
|
||||
REGULATOR_STATUS_BYPASS,
|
||||
/* in case that any other status doesn't apply */
|
||||
REGULATOR_STATUS_UNDEFINED,
|
||||
};
|
||||
|
@ -67,6 +69,9 @@ enum regulator_status {
|
|||
* @get_optimum_mode: Get the most efficient operating mode for the regulator
|
||||
* when running with the specified parameters.
|
||||
*
|
||||
* @set_bypass: Set the regulator in bypass mode.
|
||||
* @get_bypass: Get the regulator bypass mode state.
|
||||
*
|
||||
* @enable_time: Time taken for the regulator voltage output voltage to
|
||||
* stabilise after being enabled, in microseconds.
|
||||
* @set_ramp_delay: Set the ramp delay for the regulator. The driver should
|
||||
|
@ -133,6 +138,10 @@ struct regulator_ops {
|
|||
unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV,
|
||||
int output_uV, int load_uA);
|
||||
|
||||
/* control and report on bypass mode */
|
||||
int (*set_bypass)(struct regulator_dev *dev, bool enable);
|
||||
int (*get_bypass)(struct regulator_dev *dev, bool *enable);
|
||||
|
||||
/* the operations below are for configuration of regulator state when
|
||||
* its parent PMIC enters a global STANDBY/HIBERNATE state */
|
||||
|
||||
|
@ -205,6 +214,8 @@ struct regulator_desc {
|
|||
unsigned int vsel_mask;
|
||||
unsigned int enable_reg;
|
||||
unsigned int enable_mask;
|
||||
unsigned int bypass_reg;
|
||||
unsigned int bypass_mask;
|
||||
|
||||
unsigned int enable_time;
|
||||
};
|
||||
|
@ -253,6 +264,7 @@ struct regulator_dev {
|
|||
int exclusive;
|
||||
u32 use_count;
|
||||
u32 open_count;
|
||||
u32 bypass_count;
|
||||
|
||||
/* lists we belong to */
|
||||
struct list_head list; /* list of all regulators */
|
||||
|
@ -310,6 +322,8 @@ int regulator_disable_regmap(struct regulator_dev *rdev);
|
|||
int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
|
||||
unsigned int old_selector,
|
||||
unsigned int new_selector);
|
||||
int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable);
|
||||
int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable);
|
||||
|
||||
void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ struct regulator;
|
|||
* board/machine.
|
||||
* STATUS: Regulator can be enabled and disabled.
|
||||
* DRMS: Dynamic Regulator Mode Switching is enabled for this regulator.
|
||||
* BYPASS: Regulator can be put into bypass mode
|
||||
*/
|
||||
|
||||
#define REGULATOR_CHANGE_VOLTAGE 0x1
|
||||
|
@ -39,6 +40,7 @@ struct regulator;
|
|||
#define REGULATOR_CHANGE_MODE 0x4
|
||||
#define REGULATOR_CHANGE_STATUS 0x8
|
||||
#define REGULATOR_CHANGE_DRMS 0x10
|
||||
#define REGULATOR_CHANGE_BYPASS 0x20
|
||||
|
||||
/**
|
||||
* struct regulator_state - regulator state during low power system states
|
||||
|
|
Loading…
Reference in a new issue