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

Commit 65c9c4c6 authored by Vardan Mikayelyan's avatar Vardan Mikayelyan Committed by Felipe Balbi
Browse files

usb: dwc2: Add dwc2_handle_gpwrdn_intr() handler



The GPWRDN interrupts are those that occur in both Host and
Device mode while core is in hibernated state.

Export dwc2_core_init to be able to use it in GPWRDN_IDSTS
interrupt handler.

Here we have duplicated init functions in host and gadget sides
so I have left things as it was(used corresponing functions for
host and gadget), maybe in the future we'll resolve this problem
and will use dwc2_core_init for both sides.

Signed-off-by: default avatarVardan Mikayelyan <mvardan@synopsys.com>
Signed-off-by: default avatarJohn Youn <johnyoun@synopsys.com>
Signed-off-by: default avatarArtur Petrosyan <arturp@synopsys.com>
Signed-off-by: default avatarMinas Harutyunyan <hminas@synopsys.com>
Signed-off-by: default avatarGrigor Tovmasyan <tovmasya@synopsys.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent 97861781
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -1278,6 +1278,7 @@ int dwc2_hcd_get_future_frame_number(struct dwc2_hsotg *hsotg, int us);
void dwc2_hcd_connect(struct dwc2_hsotg *hsotg);
void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force);
void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup);
int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg);
int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg);
int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg);
@@ -1293,6 +1294,8 @@ static inline void dwc2_hcd_connect(struct dwc2_hsotg *hsotg) {}
static inline void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force) {}
static inline void dwc2_hcd_start(struct dwc2_hsotg *hsotg) {}
static inline void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) {}
static inline int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
{ return 0; }
static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
{ return 0; }
static inline int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
+117 −0
Original line number Diff line number Diff line
@@ -642,6 +642,116 @@ static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg)
		return 0;
}

/*
 * GPWRDN interrupt handler.
 *
 * 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)
{
	u32 gpwrdn;
	int linestate;

	gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
	/* clear all interrupt */
	dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
	linestate = (gpwrdn & GPWRDN_LINESTATE_MASK) >> GPWRDN_LINESTATE_SHIFT;
	dev_dbg(hsotg->dev,
		"%s: dwc2_handle_gpwrdwn_intr called gpwrdn= %08x\n", __func__,
		gpwrdn);

	if ((gpwrdn & GPWRDN_DISCONN_DET) &&
	    (gpwrdn & GPWRDN_DISCONN_DET_MSK) && !linestate) {
		u32 gpwrdn_tmp;

		dev_dbg(hsotg->dev, "%s: GPWRDN_DISCONN_DET\n", __func__);

		/* Switch-on voltage to the core */
		gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
		gpwrdn_tmp &= ~GPWRDN_PWRDNSWTCH;
		dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
		udelay(10);

		/* Reset core */
		gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
		gpwrdn_tmp &= ~GPWRDN_PWRDNRSTN;
		dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
		udelay(10);

		/* Disable Power Down Clamp */
		gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
		gpwrdn_tmp &= ~GPWRDN_PWRDNCLMP;
		dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
		udelay(10);

		/* Deassert reset core */
		gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
		gpwrdn_tmp |= GPWRDN_PWRDNRSTN;
		dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
		udelay(10);

		/* Disable PMU interrupt */
		gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
		gpwrdn_tmp &= ~GPWRDN_PMUINTSEL;
		dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);

		/* De-assert Wakeup Logic */
		gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
		gpwrdn_tmp &= ~GPWRDN_PMUACTV;
		dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);

		hsotg->hibernated = 0;

		if (gpwrdn & GPWRDN_IDSTS) {
			hsotg->op_state = OTG_STATE_B_PERIPHERAL;
			dwc2_core_init(hsotg, false);
			dwc2_enable_global_interrupts(hsotg);
			dwc2_hsotg_core_init_disconnected(hsotg, false);
			dwc2_hsotg_core_connect(hsotg);
		} else {
			hsotg->op_state = OTG_STATE_A_HOST;

			/* Initialize the Core for Host mode */
			dwc2_core_init(hsotg, false);
			dwc2_enable_global_interrupts(hsotg);
			dwc2_hcd_start(hsotg);
		}
	}

	if ((gpwrdn & GPWRDN_LNSTSCHG) &&
	    (gpwrdn & GPWRDN_LNSTSCHG_MSK) && linestate) {
		dev_dbg(hsotg->dev, "%s: GPWRDN_LNSTSCHG\n", __func__);
		if (hsotg->hw_params.hibernation &&
		    hsotg->hibernated) {
			if (gpwrdn & GPWRDN_IDSTS) {
				dwc2_exit_hibernation(hsotg, 0, 0, 0);
				call_gadget(hsotg, resume);
			} else {
				dwc2_exit_hibernation(hsotg, 1, 0, 1);
			}
		}
	}
	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 ((gpwrdn & GPWRDN_STS_CHGINT) &&
	    (gpwrdn & GPWRDN_STS_CHGINT_MSK) && linestate) {
		dev_dbg(hsotg->dev, "%s: GPWRDN_STS_CHGINT\n", __func__);
		if (hsotg->hw_params.hibernation &&
		    hsotg->hibernated) {
			if (gpwrdn & GPWRDN_IDSTS) {
				dwc2_exit_hibernation(hsotg, 0, 0, 0);
				call_gadget(hsotg, resume);
			} else {
				dwc2_exit_hibernation(hsotg, 1, 0, 1);
			}
		}
	}
}

/*
 * Common interrupt handler
 *
@@ -672,6 +782,13 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev)
	if (gintsts & ~GINTSTS_PRTINT)
		retval = IRQ_HANDLED;

	/* In case of hibernated state gintsts must not work */
	if (hsotg->hibernated) {
		dwc2_handle_gpwrdn_intr(hsotg);
		retval = IRQ_HANDLED;
		goto out;
	}

	if (gintsts & GINTSTS_MODEMIS)
		dwc2_handle_mode_mismatch_intr(hsotg);
	if (gintsts & GINTSTS_OTGINT)
+1 −1
Original line number Diff line number Diff line
@@ -2241,7 +2241,7 @@ static int dwc2_hcd_endpoint_reset(struct dwc2_hsotg *hsotg,
 * @hsotg:         Programming view of the DWC_otg controller
 * @initial_setup: If true then this is the first init for this instance.
 */
static int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
{
	u32 usbcfg, otgctl;
	int retval;