usb: dwc2: Fix some error handling paths

[ Upstream commit ada050c691 ]

dwc2_driver_probe() calls dwc2_lowlevel_hw_init() which deassert some reset
lines.
Should an error happen in dwc2_lowlevel_hw_init() after calling
reset_control_deassert() or in the probe after calling
dwc2_lowlevel_hw_init(), the reset lines remain deasserted.

Add some devm_add_action_or_reset() calls to re-assert the lines if needed.

Update the remove function accordingly.

This change is compile-tested only.

Fixes: 83f8da562f ("usb: dwc2: Add reset control to dwc2")
Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
Link: https://lore.kernel.org/r/c64537b5339342bd00f7c2152b8fc23792b9f95a.1683306479.git.christophe.jaillet@wanadoo.fr
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Christophe JAILLET 2023-05-05 19:15:08 +02:00 committed by Greg Kroah-Hartman
parent 98b6582b37
commit b6e30a54a5
1 changed files with 13 additions and 3 deletions

View File

@ -175,6 +175,11 @@ int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg)
return ret; return ret;
} }
static void dwc2_reset_control_assert(void *data)
{
reset_control_assert(data);
}
static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
{ {
int i, ret; int i, ret;
@ -185,6 +190,10 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
"error getting reset control\n"); "error getting reset control\n");
reset_control_deassert(hsotg->reset); reset_control_deassert(hsotg->reset);
ret = devm_add_action_or_reset(hsotg->dev, dwc2_reset_control_assert,
hsotg->reset);
if (ret)
return ret;
hsotg->reset_ecc = devm_reset_control_get_optional(hsotg->dev, "dwc2-ecc"); hsotg->reset_ecc = devm_reset_control_get_optional(hsotg->dev, "dwc2-ecc");
if (IS_ERR(hsotg->reset_ecc)) if (IS_ERR(hsotg->reset_ecc))
@ -192,6 +201,10 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
"error getting reset control for ecc\n"); "error getting reset control for ecc\n");
reset_control_deassert(hsotg->reset_ecc); reset_control_deassert(hsotg->reset_ecc);
ret = devm_add_action_or_reset(hsotg->dev, dwc2_reset_control_assert,
hsotg->reset_ecc);
if (ret)
return ret;
/* /*
* Attempt to find a generic PHY, then look for an old style * Attempt to find a generic PHY, then look for an old style
@ -306,9 +319,6 @@ static int dwc2_driver_remove(struct platform_device *dev)
if (hsotg->ll_hw_enabled) if (hsotg->ll_hw_enabled)
dwc2_lowlevel_hw_disable(hsotg); dwc2_lowlevel_hw_disable(hsotg);
reset_control_assert(hsotg->reset);
reset_control_assert(hsotg->reset_ecc);
return 0; return 0;
} }