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

Commit 65171e6e authored by Jack Pham's avatar Jack Pham Committed by Gerrit - the friendly Code Review server
Browse files

usb: dwc3-msm: Fix driver removal



When performing driver unbind, several crashes are occuring in
the dwc3_msm_remove() function. This patch fixes the following:

- Disable runtime PM first to prevent any races with any suspend/
  resume happening during removal. It also places the device in
  active state so as to avoid clk_disable() multiple times.
- Replace device_init_wakeup(dev, 0) call with device_wakeup_disable()
  which properly removes the device's wakeup source. Otherwise
  it can remain active and prevent system suspend.
- Since of_platform_populate() is called in probe to add children
  in the device tree, we must unregister them using
  device_for_each_child().
- Fix the NULL check for mdwc->ext_chg_device when calling its
  removal routines.

Change-Id: I03b6db022e5f2a6ca4b63d0eddcad532d6f1f5e7
Signed-off-by: default avatarJack Pham <jackp@codeaurora.org>
parent d61f39e2
Loading
Loading
Loading
Loading
+13 −5
Original line number Diff line number Diff line
@@ -2643,13 +2643,20 @@ disable_dwc3_gdsc:
	return ret;
}

static int dwc3_msm_remove_children(struct device *dev, void *data)
{
	device_unregister(dev);
	return 0;
}

static int dwc3_msm_remove(struct platform_device *pdev)
{
	struct dwc3_msm	*mdwc = platform_get_drvdata(pdev);

	platform_device_put(mdwc->dwc3);
	pm_runtime_disable(mdwc->dev);
	device_wakeup_disable(mdwc->dev);

	if (!mdwc->ext_chg_device) {
	if (mdwc->ext_chg_device) {
		device_destroy(mdwc->ext_chg_class, mdwc->ext_chg_dev);
		cdev_del(&mdwc->ext_chg_cdev);
		class_destroy(mdwc->ext_chg_class);
@@ -2664,12 +2671,13 @@ static int dwc3_msm_remove(struct platform_device *pdev)
		dwc3_start_chg_det(&mdwc->charger, false);
	if (mdwc->usb_psy.dev)
		power_supply_unregister(&mdwc->usb_psy);

	platform_device_put(mdwc->dwc3);
	device_for_each_child(&pdev->dev, NULL, dwc3_msm_remove_children);

	if (!IS_ERR_OR_NULL(mdwc->vbus_otg))
		regulator_disable(mdwc->vbus_otg);

	pm_runtime_disable(mdwc->dev);
	device_init_wakeup(mdwc->dev, 0);

	clk_disable_unprepare(mdwc->core_clk);
	clk_disable_unprepare(mdwc->iface_clk);
	clk_disable_unprepare(mdwc->sleep_clk);