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

backlight: lp855x: Ensure regulators are disabled on probe failure

If probing the LP885x backlight fails after the regulators have been
enabled, then the following warning is seen when releasing the
regulators ...

WARNING: CPU: 1 PID: 289 at drivers/regulator/core.c:2051 _regulator_put.part.28+0x158/0x160
Modules linked in: tegra_xudc lp855x_bl(+) host1x pwm_tegra ip_tables x_tables ipv6 nf_defrag_ipv6
CPU: 1 PID: 289 Comm: systemd-udevd Not tainted 5.6.0-rc2-next-20200224 #1
Hardware name: NVIDIA Jetson TX1 Developer Kit (DT)

...

Call trace:
_regulator_put.part.28+0x158/0x160
regulator_put+0x34/0x50
devm_regulator_release+0x10/0x18
release_nodes+0x12c/0x230
devres_release_all+0x34/0x50
really_probe+0x1c0/0x370
driver_probe_device+0x58/0x100
device_driver_attach+0x6c/0x78
__driver_attach+0xb0/0xf0
bus_for_each_dev+0x68/0xc8
driver_attach+0x20/0x28
bus_add_driver+0x160/0x1f0
driver_register+0x60/0x110
i2c_register_driver+0x40/0x80
lp855x_driver_init+0x20/0x1000 [lp855x_bl]
do_one_initcall+0x58/0x1a0
do_init_module+0x54/0x1d0
load_module+0x1d80/0x21c8
__do_sys_finit_module+0xe8/0x100
__arm64_sys_finit_module+0x18/0x20
el0_svc_common.constprop.3+0xb0/0x168
do_el0_svc+0x20/0x98
el0_sync_handler+0xf4/0x1b0
el0_sync+0x140/0x180

Fix this by ensuring that the regulators are disabled, if enabled, on
probe failure.

Finally, ensure that the vddio regulator is disabled in the driver
remove handler.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Reviewed-by: Daniel Thompson <daniel.thompson@linaro.org>
Signed-off-by: Lee Jones <lee.jones@linaro.org>

authored by

Jon Hunter and committed by
Lee Jones
d8207c15 8f3d9f35

+16 -4
+16 -4
drivers/video/backlight/lp855x_bl.c
··· 456 456 ret = regulator_enable(lp->enable); 457 457 if (ret < 0) { 458 458 dev_err(lp->dev, "failed to enable vddio: %d\n", ret); 459 - return ret; 459 + goto disable_supply; 460 460 } 461 461 462 462 /* ··· 471 471 ret = lp855x_configure(lp); 472 472 if (ret) { 473 473 dev_err(lp->dev, "device config err: %d", ret); 474 - return ret; 474 + goto disable_vddio; 475 475 } 476 476 477 477 ret = lp855x_backlight_register(lp); 478 478 if (ret) { 479 479 dev_err(lp->dev, 480 480 "failed to register backlight. err: %d\n", ret); 481 - return ret; 481 + goto disable_vddio; 482 482 } 483 483 484 484 ret = sysfs_create_group(&lp->dev->kobj, &lp855x_attr_group); 485 485 if (ret) { 486 486 dev_err(lp->dev, "failed to register sysfs. err: %d\n", ret); 487 - return ret; 487 + goto disable_vddio; 488 488 } 489 489 490 490 backlight_update_status(lp->bl); 491 + 491 492 return 0; 493 + 494 + disable_vddio: 495 + if (lp->enable) 496 + regulator_disable(lp->enable); 497 + disable_supply: 498 + if (lp->supply) 499 + regulator_disable(lp->supply); 500 + 501 + return ret; 492 502 } 493 503 494 504 static int lp855x_remove(struct i2c_client *cl) ··· 507 497 508 498 lp->bl->props.brightness = 0; 509 499 backlight_update_status(lp->bl); 500 + if (lp->enable) 501 + regulator_disable(lp->enable); 510 502 if (lp->supply) 511 503 regulator_disable(lp->supply); 512 504 sysfs_remove_group(&lp->dev->kobj, &lp855x_attr_group);