Commit 8f6862d4 authored by Mark Brown's avatar Mark Brown

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.
parents f76fe059 b8575a11
...@@ -349,3 +349,24 @@ Description: ...@@ -349,3 +349,24 @@ Description:
This will be one of the same strings reported by This will be one of the same strings reported by
the "state" attribute. 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) ...@@ -434,6 +434,11 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev)
regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
ARIZONA_JD1_ENA, ARIZONA_JD1_ENA); 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); pm_runtime_put(&pdev->dev);
return 0; return 0;
......
...@@ -39,6 +39,8 @@ static struct regulator_ops arizona_ldo1_ops = { ...@@ -39,6 +39,8 @@ static struct regulator_ops arizona_ldo1_ops = {
.map_voltage = regulator_map_voltage_linear, .map_voltage = regulator_map_voltage_linear,
.get_voltage_sel = regulator_get_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_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 = { static const struct regulator_desc arizona_ldo1 = {
...@@ -49,6 +51,8 @@ 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_reg = ARIZONA_LDO1_CONTROL_1,
.vsel_mask = ARIZONA_LDO1_VSEL_MASK, .vsel_mask = ARIZONA_LDO1_VSEL_MASK,
.bypass_reg = ARIZONA_LDO1_CONTROL_1,
.bypass_mask = ARIZONA_LDO1_BYPASS,
.min_uV = 900000, .min_uV = 900000,
.uV_step = 50000, .uV_step = 50000,
.n_voltages = 7, .n_voltages = 7,
......
...@@ -82,6 +82,9 @@ static struct regulator_ops arizona_micsupp_ops = { ...@@ -82,6 +82,9 @@ static struct regulator_ops arizona_micsupp_ops = {
.get_voltage_sel = regulator_get_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_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 = { static const struct regulator_desc arizona_micsupp = {
...@@ -95,6 +98,8 @@ static const struct regulator_desc arizona_micsupp = { ...@@ -95,6 +98,8 @@ static const struct regulator_desc arizona_micsupp = {
.vsel_mask = ARIZONA_LDO2_VSEL_MASK, .vsel_mask = ARIZONA_LDO2_VSEL_MASK,
.enable_reg = ARIZONA_MIC_CHARGE_PUMP_1, .enable_reg = ARIZONA_MIC_CHARGE_PUMP_1,
.enable_mask = ARIZONA_CPMIC_ENA, .enable_mask = ARIZONA_CPMIC_ENA,
.bypass_reg = ARIZONA_MIC_CHARGE_PUMP_1,
.bypass_mask = ARIZONA_CPMIC_BYPASS,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
......
...@@ -77,6 +77,7 @@ struct regulator { ...@@ -77,6 +77,7 @@ struct regulator {
struct device *dev; struct device *dev;
struct list_head list; struct list_head list;
unsigned int always_on:1; unsigned int always_on:1;
unsigned int bypass:1;
int uA_load; int uA_load;
int min_uV; int min_uV;
int max_uV; int max_uV;
...@@ -394,6 +395,9 @@ static ssize_t regulator_status_show(struct device *dev, ...@@ -394,6 +395,9 @@ static ssize_t regulator_status_show(struct device *dev,
case REGULATOR_STATUS_STANDBY: case REGULATOR_STATUS_STANDBY:
label = "standby"; label = "standby";
break; break;
case REGULATOR_STATUS_BYPASS:
label = "bypass";
break;
case REGULATOR_STATUS_UNDEFINED: case REGULATOR_STATUS_UNDEFINED:
label = "undefined"; label = "undefined";
break; break;
...@@ -585,6 +589,27 @@ static ssize_t regulator_suspend_standby_state_show(struct device *dev, ...@@ -585,6 +589,27 @@ static ssize_t regulator_suspend_standby_state_show(struct device *dev,
static DEVICE_ATTR(suspend_standby_state, 0444, static DEVICE_ATTR(suspend_standby_state, 0444,
regulator_suspend_standby_state_show, NULL); 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. * These are the only attributes are present for all regulators.
...@@ -2673,6 +2698,100 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) ...@@ -2673,6 +2698,100 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
} }
EXPORT_SYMBOL_GPL(regulator_set_optimum_mode); 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_register_notifier - register regulator event notifier
* @regulator: regulator source * @regulator: regulator source
...@@ -3036,6 +3155,11 @@ static int add_regulator_attributes(struct regulator_dev *rdev) ...@@ -3036,6 +3155,11 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
if (status < 0) if (status < 0)
return status; return status;
} }
if (ops->get_bypass) {
status = device_create_file(dev, &dev_attr_bypass);
if (status < 0)
return status;
}
/* some attributes are type-specific */ /* some attributes are type-specific */
if (rdev->desc->type == REGULATOR_CURRENT) { if (rdev->desc->type == REGULATOR_CURRENT) {
...@@ -3124,6 +3248,8 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) ...@@ -3124,6 +3248,8 @@ static void rdev_init_debugfs(struct regulator_dev *rdev)
&rdev->use_count); &rdev->use_count);
debugfs_create_u32("open_count", 0444, rdev->debugfs, debugfs_create_u32("open_count", 0444, rdev->debugfs,
&rdev->open_count); &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 = { ...@@ -237,6 +237,8 @@ static struct regulator_ops wm831x_gp_ldo_ops = {
.set_mode = wm831x_gp_ldo_set_mode, .set_mode = wm831x_gp_ldo_set_mode,
.get_status = wm831x_gp_ldo_get_status, .get_status = wm831x_gp_ldo_get_status,
.get_optimum_mode = wm831x_gp_ldo_get_optimum_mode, .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, .is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap, .enable = regulator_enable_regmap,
...@@ -293,6 +295,8 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev) ...@@ -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.vsel_mask = WM831X_LDO1_ON_VSEL_MASK;
ldo->desc.enable_reg = WM831X_LDO_ENABLE; ldo->desc.enable_reg = WM831X_LDO_ENABLE;
ldo->desc.enable_mask = 1 << id; ldo->desc.enable_mask = 1 << id;
ldo->desc.bypass_reg = ldo->base;
ldo->desc.bypass_mask = WM831X_LDO1_SWI;
config.dev = pdev->dev.parent; config.dev = pdev->dev.parent;
if (pdata) if (pdata)
...@@ -488,6 +492,8 @@ static struct regulator_ops wm831x_aldo_ops = { ...@@ -488,6 +492,8 @@ static struct regulator_ops wm831x_aldo_ops = {
.get_mode = wm831x_aldo_get_mode, .get_mode = wm831x_aldo_get_mode,
.set_mode = wm831x_aldo_set_mode, .set_mode = wm831x_aldo_set_mode,
.get_status = wm831x_aldo_get_status, .get_status = wm831x_aldo_get_status,
.set_bypass = regulator_set_bypass_regmap,
.get_bypass = regulator_get_bypass_regmap,
.is_enabled = regulator_is_enabled_regmap, .is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap, .enable = regulator_enable_regmap,
...@@ -544,6 +550,8 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev) ...@@ -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.vsel_mask = WM831X_LDO7_ON_VSEL_MASK;
ldo->desc.enable_reg = WM831X_LDO_ENABLE; ldo->desc.enable_reg = WM831X_LDO_ENABLE;
ldo->desc.enable_mask = 1 << id; ldo->desc.enable_mask = 1 << id;
ldo->desc.bypass_reg = ldo->base;
ldo->desc.bypass_mask = WM831X_LDO7_SWI;
config.dev = pdev->dev.parent; config.dev = pdev->dev.parent;
if (pdata) if (pdata)
......
...@@ -177,6 +177,8 @@ int regulator_set_mode(struct regulator *regulator, unsigned int mode); ...@@ -177,6 +177,8 @@ int regulator_set_mode(struct regulator *regulator, unsigned int mode);
unsigned int regulator_get_mode(struct regulator *regulator); unsigned int regulator_get_mode(struct regulator *regulator);
int regulator_set_optimum_mode(struct regulator *regulator, int load_uA); int regulator_set_optimum_mode(struct regulator *regulator, int load_uA);
int regulator_allow_bypass(struct regulator *regulator, bool allow);
/* regulator notifier block */ /* regulator notifier block */
int regulator_register_notifier(struct regulator *regulator, int regulator_register_notifier(struct regulator *regulator,
struct notifier_block *nb); struct notifier_block *nb);
...@@ -328,6 +330,12 @@ static inline int regulator_set_optimum_mode(struct regulator *regulator, ...@@ -328,6 +330,12 @@ static inline int regulator_set_optimum_mode(struct regulator *regulator,
return REGULATOR_MODE_NORMAL; 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, static inline int regulator_register_notifier(struct regulator *regulator,
struct notifier_block *nb) struct notifier_block *nb)
{ {
......
...@@ -32,6 +32,8 @@ enum regulator_status { ...@@ -32,6 +32,8 @@ enum regulator_status {
REGULATOR_STATUS_NORMAL, REGULATOR_STATUS_NORMAL,
REGULATOR_STATUS_IDLE, REGULATOR_STATUS_IDLE,
REGULATOR_STATUS_STANDBY, REGULATOR_STATUS_STANDBY,
/* The regulator is enabled but not regulating */
REGULATOR_STATUS_BYPASS,
/* in case that any other status doesn't apply */ /* in case that any other status doesn't apply */
REGULATOR_STATUS_UNDEFINED, REGULATOR_STATUS_UNDEFINED,
}; };
...@@ -67,6 +69,9 @@ enum regulator_status { ...@@ -67,6 +69,9 @@ enum regulator_status {
* @get_optimum_mode: Get the most efficient operating mode for the regulator * @get_optimum_mode: Get the most efficient operating mode for the regulator
* when running with the specified parameters. * 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 * @enable_time: Time taken for the regulator voltage output voltage to
* stabilise after being enabled, in microseconds. * stabilise after being enabled, in microseconds.
* @set_ramp_delay: Set the ramp delay for the regulator. The driver should * @set_ramp_delay: Set the ramp delay for the regulator. The driver should
...@@ -133,6 +138,10 @@ struct regulator_ops { ...@@ -133,6 +138,10 @@ struct regulator_ops {
unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV, unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV,
int output_uV, int load_uA); 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 /* the operations below are for configuration of regulator state when
* its parent PMIC enters a global STANDBY/HIBERNATE state */ * its parent PMIC enters a global STANDBY/HIBERNATE state */
...@@ -205,6 +214,8 @@ struct regulator_desc { ...@@ -205,6 +214,8 @@ struct regulator_desc {
unsigned int vsel_mask; unsigned int vsel_mask;
unsigned int enable_reg; unsigned int enable_reg;
unsigned int enable_mask; unsigned int enable_mask;
unsigned int bypass_reg;
unsigned int bypass_mask;
unsigned int enable_time; unsigned int enable_time;
}; };
...@@ -253,6 +264,7 @@ struct regulator_dev { ...@@ -253,6 +264,7 @@ struct regulator_dev {
int exclusive; int exclusive;
u32 use_count; u32 use_count;
u32 open_count; u32 open_count;
u32 bypass_count;
/* lists we belong to */ /* lists we belong to */
struct list_head list; /* list of all regulators */ struct list_head list; /* list of all regulators */
...@@ -310,6 +322,8 @@ int regulator_disable_regmap(struct regulator_dev *rdev); ...@@ -310,6 +322,8 @@ int regulator_disable_regmap(struct regulator_dev *rdev);
int regulator_set_voltage_time_sel(struct regulator_dev *rdev, int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
unsigned int old_selector, unsigned int old_selector,
unsigned int new_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); void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
......
...@@ -32,6 +32,7 @@ struct regulator; ...@@ -32,6 +32,7 @@ struct regulator;
* board/machine. * board/machine.
* STATUS: Regulator can be enabled and disabled. * STATUS: Regulator can be enabled and disabled.
* DRMS: Dynamic Regulator Mode Switching is enabled for this regulator. * DRMS: Dynamic Regulator Mode Switching is enabled for this regulator.
* BYPASS: Regulator can be put into bypass mode
*/ */
#define REGULATOR_CHANGE_VOLTAGE 0x1 #define REGULATOR_CHANGE_VOLTAGE 0x1
...@@ -39,6 +40,7 @@ struct regulator; ...@@ -39,6 +40,7 @@ struct regulator;
#define REGULATOR_CHANGE_MODE 0x4 #define REGULATOR_CHANGE_MODE 0x4
#define REGULATOR_CHANGE_STATUS 0x8 #define REGULATOR_CHANGE_STATUS 0x8
#define REGULATOR_CHANGE_DRMS 0x10 #define REGULATOR_CHANGE_DRMS 0x10
#define REGULATOR_CHANGE_BYPASS 0x20
/** /**
* struct regulator_state - regulator state during low power system states * struct regulator_state - regulator state during low power system states
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment