Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 202b5689 authored by Viresh Kumar's avatar Viresh Kumar Committed by Lee Jones
Browse files

mfd: wm8994-core: Don't use managed regulator bulk get API



The kernel WARNs and then crashes today if wm8994_device_init() fails
after calling devm_regulator_bulk_get().

That happens because there are multiple devices involved here and the
order in which managed resources are freed isn't correct.

The regulators are added as children of wm8994->dev.  Whereas,
devm_regulator_bulk_get() receives wm8994->dev as the device, though it
gets the same regulators which were added as children of wm8994->dev
earlier.

During failures, the children are removed first and the core eventually
calls regulator_unregister() for them. As regulator_put() was never done
for them (opposite of devm_regulator_bulk_get()), the kernel WARNs at

	WARN_ON(rdev->open_count);

And eventually it crashes from debugfs_remove_recursive().

Fix the kernel warnings and crashes by using regulator_bulk_get()
instead of devm_regulator_bulk_get() and explicitly freeing the supplies
in exit paths.

Tested on Exynos 5250, dual core ARM A15 machine.

Signed-off-by: default avatarViresh Kumar <viresh.kumar@linaro.org>
Acked-by: default avatarCharles Keepax <ckeepax@opensource.wolfsonmicro.com>
Signed-off-by: default avatarLee Jones <lee.jones@linaro.org>
parent 8ca9edc8
Loading
Loading
Loading
Loading
+11 −3
Original line number Diff line number Diff line
@@ -394,7 +394,12 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
		goto err;
	}

	ret = devm_regulator_bulk_get(wm8994->dev, wm8994->num_supplies,
	/*
	 * Can't use devres helper here as some of the supplies are provided by
	 * wm8994->dev's children (regulators) and those regulators are
	 * unregistered by the devres core before the supplies are freed.
	 */
	ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies,
				 wm8994->supplies);
	if (ret != 0) {
		dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret);
@@ -404,7 +409,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
	ret = regulator_bulk_enable(wm8994->num_supplies, wm8994->supplies);
	if (ret != 0) {
		dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret);
		goto err;
		goto err_regulator_free;
	}

	ret = wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET);
@@ -595,6 +600,8 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
err_enable:
	regulator_bulk_disable(wm8994->num_supplies,
			       wm8994->supplies);
err_regulator_free:
	regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
err:
	mfd_remove_devices(wm8994->dev);
	return ret;
@@ -605,6 +612,7 @@ static void wm8994_device_exit(struct wm8994 *wm8994)
	pm_runtime_disable(wm8994->dev);
	wm8994_irq_exit(wm8994);
	regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies);
	regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
	mfd_remove_devices(wm8994->dev);
}