Ejemplo n.º 1
0
/*
 * This interrupt indicates that the DWC_otg controller has detected a
 * resume or remote wakeup sequence. If the DWC_otg controller is in
 * low power mode, the handler must brings the controller out of low
 * power mode. The controller automatically begins resume signaling.
 * The handler schedules a time to stop resume signaling.
 */
static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
{
    int ret;
    dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n");
    dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);

    if (dwc2_is_device_mode(hsotg)) {
        dev_dbg(hsotg->dev, "DSTS=0x%0x\n", DWC2_READ_4(hsotg, DSTS));
        if (hsotg->lx_state == DWC2_L2) {
            u32 dctl = DWC2_READ_4(hsotg, DCTL);

            /* Clear Remote Wakeup Signaling */
            dctl &= ~DCTL_RMTWKUPSIG;
            DWC2_WRITE_4(hsotg, DCTL, dctl);
            ret = dwc2_exit_hibernation(hsotg, true);
            if (ret && (ret != -ENOTSUPP))
                dev_err(hsotg->dev, "exit hibernation failed\n");

            call_gadget(hsotg, resume);
        }
        /* Change to L0 state */
        hsotg->lx_state = DWC2_L0;
    } else {
        if (hsotg->lx_state != DWC2_L1) {
            u32 pcgcctl = DWC2_READ_4(hsotg, PCGCTL);

            /* Restart the Phy Clock */
            pcgcctl &= ~PCGCTL_STOPPCLK;
            DWC2_WRITE_4(hsotg, PCGCTL, pcgcctl);
            callout_reset(&hsotg->wkp_timer, mstohz(71),
                          dwc2_wakeup_detected, hsotg);
        } else {
            /* Change to L0 state */
            hsotg->lx_state = DWC2_L0;
        }
    }

    /* Clear interrupt */
    DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_WKUPINT);
}
Ejemplo n.º 2
0
/*
 * This interrupt indicates that the DWC_otg controller has detected a
 * resume or remote wakeup sequence. If the DWC_otg controller is in
 * low power mode, the handler must brings the controller out of low
 * power mode. The controller automatically begins resume signaling.
 * The handler schedules a time to stop resume signaling.
 */
static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
{
	int ret;
	dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n");
	dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);

	if (dwc2_is_device_mode(hsotg)) {
		dev_dbg(hsotg->dev, "DSTS=0x%0x\n", readl(hsotg->regs + DSTS));
		if (hsotg->lx_state == DWC2_L2) {
			u32 dctl = readl(hsotg->regs + DCTL);

			/* Clear Remote Wakeup Signaling */
			dctl &= ~DCTL_RMTWKUPSIG;
			writel(dctl, hsotg->regs + DCTL);
			ret = dwc2_exit_hibernation(hsotg, true);
			if (ret && (ret != -ENOTSUPP))
				dev_err(hsotg->dev, "exit hibernation failed\n");

			call_gadget(hsotg, resume);
		}
		/* Change to L0 state */
		hsotg->lx_state = DWC2_L0;
	} else {
		if (hsotg->lx_state != DWC2_L1) {
			u32 pcgcctl = readl(hsotg->regs + PCGCTL);

			/* Restart the Phy Clock */
			pcgcctl &= ~PCGCTL_STOPPCLK;
			writel(pcgcctl, hsotg->regs + PCGCTL);
			mod_timer(&hsotg->wkp_timer,
				  jiffies + msecs_to_jiffies(71));
		} else {
			/* Change to L0 state */
			hsotg->lx_state = DWC2_L0;
		}
	}

	/* Clear interrupt */
	writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS);
}
Ejemplo n.º 3
0
/*
 * This interrupt indicates that SUSPEND state has been detected on the USB.
 *
 * For HNP the USB Suspend interrupt signals the change from "a_peripheral"
 * to "a_host".
 *
 * When power management is enabled the core will be put in low power mode.
 */
static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
{
    u32 dsts;
    int ret;

    dev_dbg(hsotg->dev, "USB SUSPEND\n");

    if (dwc2_is_device_mode(hsotg)) {
        /*
         * Check the Device status register to determine if the Suspend
         * state is active
         */
        dsts = DWC2_READ_4(hsotg, DSTS);
        dev_dbg(hsotg->dev, "DSTS=0x%0x\n", dsts);
        dev_dbg(hsotg->dev,
                "DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n",
                !!(dsts & DSTS_SUSPSTS),
                hsotg->hw_params.power_optimized);
        if ((dsts & DSTS_SUSPSTS) && hsotg->hw_params.power_optimized) {
            /* Ignore suspend request before enumeration */
            if (!dwc2_is_device_connected(hsotg)) {
                dev_dbg(hsotg->dev,
                        "ignore suspend request before enumeration\n");
                goto clear_int;
            }

            ret = dwc2_enter_hibernation(hsotg);
            if (ret) {
                if (ret != -ENOTSUPP)
                    dev_err(hsotg->dev,
                            "enter hibernation failed\n");
                goto skip_power_saving;
            }

            udelay(100);

            /* Ask phy to be suspended */
            if (!IS_ERR_OR_NULL(hsotg->uphy))
                usb_phy_set_suspend(hsotg->uphy, true);
skip_power_saving:
            /*
             * Change to L2 (suspend) state before releasing
             * spinlock
             */
            hsotg->lx_state = DWC2_L2;

            /* Call gadget suspend callback */
            call_gadget(hsotg, suspend);
        }
    } else {
        if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) {
            dev_dbg(hsotg->dev, "a_peripheral->a_host\n");

            /* Change to L2 (suspend) state */
            hsotg->lx_state = DWC2_L2;
            /* Clear the a_peripheral flag, back to a_host */
            spin_unlock(&hsotg->lock);
            dwc2_hcd_start(hsotg);
            spin_lock(&hsotg->lock);
            hsotg->op_state = OTG_STATE_A_HOST;
        }
    }

clear_int:
    /* Clear interrupt */
    DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_USBSUSP);
}