summaryrefslogtreecommitdiff
path: root/drivers/usb/dwc2
diff options
context:
space:
mode:
authorArtur Petrosyan <Arthur.Petrosyan@synopsys.com>2021-04-16 15:48:26 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-04-22 12:55:34 +0300
commita94f01814be4fb46fb89c08209f808b665182763 (patch)
treee0cc5dd70203d5114584524908fd8666347a782c /drivers/usb/dwc2
parentae0da4fd225804a2c5c60a03b16fcf7d930d8581 (diff)
downloadlinux-a94f01814be4fb46fb89c08209f808b665182763.tar.xz
usb: dwc2: Add exit hibernation mode before removing drive
When dwc2 core is in hibernation mode loading driver again causes driver fail. Because in that mode registers are not accessible. In order to exit from hibernation checking dwc2 core power saving state in "dwc2_driver_remove()" function. If core is in hibernation, then checking the operational mode of the driver. To check whether dwc2 core is operating in host mode or device mode there is one way which is retrieving the backup value of "gotgctl" and compare the "CurMod" value. If previously core entered hibernation in host mode then the exit is performed for host if not then exit is performed for device mode. The introduced checking is because in hibernation state all registers are not accessible. Reported-by: kernel test robot <lkp@intel.com> Reported-by: Dan Carpenter <dan.carpenter@oracle.com> Acked-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com> Signed-off-by: Artur Petrosyan <Arthur.Petrosyan@synopsys.com> Link: https://lore.kernel.org/r/20210416124827.9BB59A005D@mailhost.synopsys.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/dwc2')
-rw-r--r--drivers/usb/dwc2/platform.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 1249a2307fba..3024785d84cb 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -316,8 +316,23 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
static int dwc2_driver_remove(struct platform_device *dev)
{
struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
+ struct dwc2_gregs_backup *gr;
int ret = 0;
+ gr = &hsotg->gr_backup;
+
+ /* Exit Hibernation when driver is removed. */
+ if (hsotg->hibernated) {
+ if (gr->gotgctl & GOTGCTL_CURMODE_HOST)
+ ret = dwc2_exit_hibernation(hsotg, 0, 0, 1);
+ else
+ ret = dwc2_exit_hibernation(hsotg, 0, 0, 0);
+
+ if (ret)
+ dev_err(hsotg->dev,
+ "exit hibernation failed.\n");
+ }
+
/* Exit Partial Power Down when driver is removed. */
if (hsotg->in_ppd) {
ret = dwc2_exit_partial_power_down(hsotg, 0, true);