Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Lucas Stach and committed by
Sebastian Reichel
a3d70dac 3c9c2d08

+38 -4
+38 -4
drivers/power/supply/ucs1002_power.c
··· 100 100 struct i2c_client *client; 101 101 struct regmap *regmap; 102 102 struct regulator_desc *regulator_descriptor; 103 + struct regulator_dev *rdev; 103 104 bool present; 105 + bool output_disable; 104 106 }; 105 107 106 108 static enum power_supply_property ucs1002_props[] = { ··· 235 233 unsigned int reg; 236 234 int ret; 237 235 236 + if (info->output_disable) { 237 + val->intval = 0; 238 + return 0; 239 + } 240 + 238 241 ret = regmap_read(info->regmap, UCS1002_REG_ILIMIT, &reg); 239 242 if (ret) 240 243 return ret; ··· 253 246 { 254 247 unsigned int reg; 255 248 int ret, idx; 249 + 250 + if (val == 0) { 251 + info->output_disable = true; 252 + regulator_disable_regmap(info->rdev); 253 + return 0; 254 + } 256 255 257 256 for (idx = 0; idx < ARRAY_SIZE(ucs1002_current_limit_uA); idx++) { 258 257 if (val == ucs1002_current_limit_uA[idx]) ··· 282 269 283 270 if (reg != idx) 284 271 return -EINVAL; 272 + 273 + info->output_disable = false; 274 + 275 + if (info->rdev && info->rdev->use_count && 276 + !regulator_is_enabled_regmap(info->rdev)) 277 + regulator_enable_regmap(info->rdev); 285 278 286 279 return 0; 287 280 } ··· 489 470 return IRQ_HANDLED; 490 471 } 491 472 473 + int ucs1002_regulator_enable(struct regulator_dev *rdev) 474 + { 475 + struct ucs1002_info *info = rdev_get_drvdata(rdev); 476 + 477 + /* 478 + * If the output is disabled due to 0 maximum current, just pretend the 479 + * enable did work. The regulator will be enabled as soon as we get a 480 + * a non-zero maximum current budget. 481 + */ 482 + if (info->output_disable) 483 + return 0; 484 + 485 + return regulator_enable_regmap(rdev); 486 + } 487 + 492 488 static const struct regulator_ops ucs1002_regulator_ops = { 493 489 .is_enabled = regulator_is_enabled_regmap, 494 - .enable = regulator_enable_regmap, 490 + .enable = ucs1002_regulator_enable, 495 491 .disable = regulator_disable_regmap, 496 492 }; 497 493 ··· 533 499 }; 534 500 struct regulator_config regulator_config = {}; 535 501 int irq_a_det, irq_alert, ret; 536 - struct regulator_dev *rdev; 537 502 struct ucs1002_info *info; 538 503 unsigned int regval; 539 504 ··· 622 589 regulator_config.dev = dev; 623 590 regulator_config.of_node = dev->of_node; 624 591 regulator_config.regmap = info->regmap; 592 + regulator_config.driver_data = info; 625 593 626 - rdev = devm_regulator_register(dev, info->regulator_descriptor, 594 + info->rdev = devm_regulator_register(dev, info->regulator_descriptor, 627 595 &regulator_config); 628 - ret = PTR_ERR_OR_ZERO(rdev); 596 + ret = PTR_ERR_OR_ZERO(info->rdev); 629 597 if (ret) { 630 598 dev_err(dev, "Failed to register VBUS regulator: %d\n", ret); 631 599 return ret;