Commit 4111d5f8 authored by Artur Petrosyan's avatar Artur Petrosyan Committed by Greg Kroah-Hartman
Browse files

usb: dwc2: Allow exiting hibernation from gpwrdn rst detect



When device cable is disconnected core receives suspend
interrupt and enters hibernation. After entering
into hibernation GPWRDN_RST_DET and GPWRDN_STS_CHGINT
interrupts are asserted.

Allowed exit from gadget hibernation from
GPWRDN_RST_DET by checking only linestate.

Changed the return type of "dwc2_handle_gpwrdn_intr()"
function from void to int because exit from hibernation
functions have a return value.

Acked-by: default avatarMinas Harutyunyan <Minas.Harutyunyan@synopsys.com>
Signed-off-by: default avatarArtur Petrosyan <Arthur.Petrosyan@synopsys.com>
Link: https://lore.kernel.org/r/20210416124723.B6F17A005C@mailhost.synopsys.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 24d209db
Loading
Loading
Loading
Loading
+18 −5
Original line number Diff line number Diff line
@@ -751,10 +751,11 @@ static inline void dwc_handle_gpwrdn_disc_det(struct dwc2_hsotg *hsotg,
 * The GPWRDN interrupts are those that occur in both Host and
 * Device mode while core is in hibernated state.
 */
static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)
static int dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)
{
	u32 gpwrdn;
	int linestate;
	int ret = 0;

	gpwrdn = dwc2_readl(hsotg, GPWRDN);
	/* clear all interrupt */
@@ -778,17 +779,27 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)
		if (hsotg->hw_params.hibernation &&
		    hsotg->hibernated) {
			if (gpwrdn & GPWRDN_IDSTS) {
				dwc2_exit_hibernation(hsotg, 0, 0, 0);
				ret = dwc2_exit_hibernation(hsotg, 0, 0, 0);
				if (ret)
					dev_err(hsotg->dev,
						"exit hibernation failed.\n");
				call_gadget(hsotg, resume);
			} else {
				dwc2_exit_hibernation(hsotg, 1, 0, 1);
				ret = dwc2_exit_hibernation(hsotg, 1, 0, 1);
				if (ret)
					dev_err(hsotg->dev,
						"exit hibernation failed.\n");
			}
		}
	} else if ((gpwrdn & GPWRDN_RST_DET) &&
		   (gpwrdn & GPWRDN_RST_DET_MSK)) {
		dev_dbg(hsotg->dev, "%s: GPWRDN_RST_DET\n", __func__);
		if (!linestate && (gpwrdn & GPWRDN_BSESSVLD))
			dwc2_exit_hibernation(hsotg, 0, 1, 0);
		if (!linestate) {
			ret = dwc2_exit_hibernation(hsotg, 0, 1, 0);
			if (ret)
				dev_err(hsotg->dev,
					"exit hibernation failed.\n");
		}
	} else if ((gpwrdn & GPWRDN_STS_CHGINT) &&
		   (gpwrdn & GPWRDN_STS_CHGINT_MSK)) {
		dev_dbg(hsotg->dev, "%s: GPWRDN_STS_CHGINT\n", __func__);
@@ -800,6 +811,8 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)
		 */
		dwc_handle_gpwrdn_disc_det(hsotg, gpwrdn);
	}

	return ret;
}

/*