mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 08:19:28 +00:00
power: suppy: ucs1002: disable power when max current is 0
For some devices userspace needs the ability to completely cut the power to the USB devices connected to the charge controller. An easy way to achieve this is by allowing 0 as a valid max current and forcibly disable the output in that case, as well as enable it again if the regulator is in use and a non-0 max current is set. Signed-off-by: Lucas Stach <l.stach@pengutronix.de> Tested-by: Chris Healy <cphealy@gmail.com> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
This commit is contained in:
parent
3c9c2d0812
commit
a3d70dacc7
1 changed files with 38 additions and 4 deletions
|
@ -100,7 +100,9 @@ struct ucs1002_info {
|
|||
struct i2c_client *client;
|
||||
struct regmap *regmap;
|
||||
struct regulator_desc *regulator_descriptor;
|
||||
struct regulator_dev *rdev;
|
||||
bool present;
|
||||
bool output_disable;
|
||||
};
|
||||
|
||||
static enum power_supply_property ucs1002_props[] = {
|
||||
|
@ -233,6 +235,11 @@ static int ucs1002_get_max_current(struct ucs1002_info *info,
|
|||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
if (info->output_disable) {
|
||||
val->intval = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = regmap_read(info->regmap, UCS1002_REG_ILIMIT, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -247,6 +254,12 @@ static int ucs1002_set_max_current(struct ucs1002_info *info, u32 val)
|
|||
unsigned int reg;
|
||||
int ret, idx;
|
||||
|
||||
if (val == 0) {
|
||||
info->output_disable = true;
|
||||
regulator_disable_regmap(info->rdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (idx = 0; idx < ARRAY_SIZE(ucs1002_current_limit_uA); idx++) {
|
||||
if (val == ucs1002_current_limit_uA[idx])
|
||||
break;
|
||||
|
@ -270,6 +283,12 @@ static int ucs1002_set_max_current(struct ucs1002_info *info, u32 val)
|
|||
if (reg != idx)
|
||||
return -EINVAL;
|
||||
|
||||
info->output_disable = false;
|
||||
|
||||
if (info->rdev && info->rdev->use_count &&
|
||||
!regulator_is_enabled_regmap(info->rdev))
|
||||
regulator_enable_regmap(info->rdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -470,9 +489,24 @@ static irqreturn_t ucs1002_alert_irq(int irq, void *data)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int ucs1002_regulator_enable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct ucs1002_info *info = rdev_get_drvdata(rdev);
|
||||
|
||||
/*
|
||||
* If the output is disabled due to 0 maximum current, just pretend the
|
||||
* enable did work. The regulator will be enabled as soon as we get a
|
||||
* a non-zero maximum current budget.
|
||||
*/
|
||||
if (info->output_disable)
|
||||
return 0;
|
||||
|
||||
return regulator_enable_regmap(rdev);
|
||||
}
|
||||
|
||||
static const struct regulator_ops ucs1002_regulator_ops = {
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.enable = regulator_enable_regmap,
|
||||
.enable = ucs1002_regulator_enable,
|
||||
.disable = regulator_disable_regmap,
|
||||
};
|
||||
|
||||
|
@ -499,7 +533,6 @@ static int ucs1002_probe(struct i2c_client *client,
|
|||
};
|
||||
struct regulator_config regulator_config = {};
|
||||
int irq_a_det, irq_alert, ret;
|
||||
struct regulator_dev *rdev;
|
||||
struct ucs1002_info *info;
|
||||
unsigned int regval;
|
||||
|
||||
|
@ -589,10 +622,11 @@ static int ucs1002_probe(struct i2c_client *client,
|
|||
regulator_config.dev = dev;
|
||||
regulator_config.of_node = dev->of_node;
|
||||
regulator_config.regmap = info->regmap;
|
||||
regulator_config.driver_data = info;
|
||||
|
||||
rdev = devm_regulator_register(dev, info->regulator_descriptor,
|
||||
info->rdev = devm_regulator_register(dev, info->regulator_descriptor,
|
||||
®ulator_config);
|
||||
ret = PTR_ERR_OR_ZERO(rdev);
|
||||
ret = PTR_ERR_OR_ZERO(info->rdev);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register VBUS regulator: %d\n", ret);
|
||||
return ret;
|
||||
|
|
Loading…
Reference in a new issue