* dwc2_exit_partial_power_down() - Exit controller from Partial Power Down.
*
* @hsotg: Programming view of the DWC_otg controller
+ * @rem_wakeup: indicates whether resume is initiated by Reset.
* @restore: Controller registers need to be restored
*/
-int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore)
+int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, int rem_wakeup,
+ bool restore)
{
- u32 pcgcctl;
- int ret = 0;
-
- if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL)
- return -ENOTSUPP;
-
- pcgcctl = dwc2_readl(hsotg, PCGCTL);
- pcgcctl &= ~PCGCTL_STOPPCLK;
- dwc2_writel(hsotg, pcgcctl, PCGCTL);
-
- pcgcctl = dwc2_readl(hsotg, PCGCTL);
- pcgcctl &= ~PCGCTL_PWRCLMP;
- dwc2_writel(hsotg, pcgcctl, PCGCTL);
-
- pcgcctl = dwc2_readl(hsotg, PCGCTL);
- pcgcctl &= ~PCGCTL_RSTPDWNMODULE;
- dwc2_writel(hsotg, pcgcctl, PCGCTL);
+ struct dwc2_gregs_backup *gr;
- udelay(100);
- if (restore) {
- ret = dwc2_restore_global_registers(hsotg);
- if (ret) {
- dev_err(hsotg->dev, "%s: failed to restore registers\n",
- __func__);
- return ret;
- }
- if (dwc2_is_host_mode(hsotg)) {
- ret = dwc2_restore_host_registers(hsotg);
- if (ret) {
- dev_err(hsotg->dev, "%s: failed to restore host registers\n",
- __func__);
- return ret;
- }
- } else {
- ret = dwc2_restore_device_registers(hsotg, 0);
- if (ret) {
- dev_err(hsotg->dev, "%s: failed to restore device registers\n",
- __func__);
- return ret;
- }
- }
- }
+ gr = &hsotg->gr_backup;
- return ret;
+ /*
+ * Restore host or device regisers with the same mode core enterted
+ * to partial power down by checking "GOTGCTL_CURMODE_HOST" backup
+ * value of the "gotgctl" register.
+ */
+ if (gr->gotgctl & GOTGCTL_CURMODE_HOST)
+ return dwc2_host_exit_partial_power_down(hsotg, rem_wakeup,
+ restore);
+ else
+ return dwc2_gadget_exit_partial_power_down(hsotg, restore);
}
/**
*/
int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg)
{
- u32 pcgcctl;
- int ret = 0;
-
- if (!hsotg->params.power_down)
- return -ENOTSUPP;
-
- /* Backup all registers */
- ret = dwc2_backup_global_registers(hsotg);
- if (ret) {
- dev_err(hsotg->dev, "%s: failed to backup global registers\n",
- __func__);
- return ret;
- }
-
- if (dwc2_is_host_mode(hsotg)) {
- ret = dwc2_backup_host_registers(hsotg);
- if (ret) {
- dev_err(hsotg->dev, "%s: failed to backup host registers\n",
- __func__);
- return ret;
- }
- } else {
- ret = dwc2_backup_device_registers(hsotg);
- if (ret) {
- dev_err(hsotg->dev, "%s: failed to backup device registers\n",
- __func__);
- return ret;
- }
- }
-
- /*
- * Clear any pending interrupts since dwc2 will not be able to
- * clear them after entering partial_power_down.
- */
- dwc2_writel(hsotg, 0xffffffff, GINTSTS);
-
- /* Put the controller in low power state */
- pcgcctl = dwc2_readl(hsotg, PCGCTL);
-
- pcgcctl |= PCGCTL_PWRCLMP;
- dwc2_writel(hsotg, pcgcctl, PCGCTL);
- ndelay(20);
-
- pcgcctl |= PCGCTL_RSTPDWNMODULE;
- dwc2_writel(hsotg, pcgcctl, PCGCTL);
- ndelay(20);
-
- pcgcctl |= PCGCTL_STOPPCLK;
- dwc2_writel(hsotg, pcgcctl, PCGCTL);
-
- return ret;
+ if (dwc2_is_host_mode(hsotg))
+ return dwc2_host_enter_partial_power_down(hsotg);
+ else
+ return dwc2_gadget_enter_partial_power_down(hsotg);
}
/**
*/
int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait);
int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg);
-int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore);
+int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, int rem_wakeup,
+ bool restore);
int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host);
int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
int reset, int is_host);
hsotg->lx_state);
if (dwc2_is_device_mode(hsotg)) {
- if (hsotg->lx_state == DWC2_L2) {
- ret = dwc2_exit_partial_power_down(hsotg, true);
- if (ret && (ret != -ENOTSUPP))
+ if (hsotg->lx_state == DWC2_L2 && hsotg->in_ppd) {
+ ret = dwc2_exit_partial_power_down(hsotg, 0,
+ true);
+ if (ret)
dev_err(hsotg->dev,
"exit power_down failed\n");
}
if (dwc2_is_device_mode(hsotg)) {
dev_dbg(hsotg->dev, "DSTS=0x%0x\n",
dwc2_readl(hsotg, DSTS));
- if (hsotg->lx_state == DWC2_L2) {
+ if (hsotg->lx_state == DWC2_L2 && hsotg->in_ppd) {
u32 dctl = dwc2_readl(hsotg, DCTL);
-
/* Clear Remote Wakeup Signaling */
dctl &= ~DCTL_RMTWKUPSIG;
dwc2_writel(hsotg, dctl, DCTL);
- ret = dwc2_exit_partial_power_down(hsotg, true);
- if (ret && (ret != -ENOTSUPP))
- dev_err(hsotg->dev, "exit power_down failed\n");
-
- /* Change to L0 state */
- hsotg->lx_state = DWC2_L0;
+ ret = dwc2_exit_partial_power_down(hsotg, 1,
+ true);
+ if (ret)
+ dev_err(hsotg->dev,
+ "exit partial_power_down failed\n");
call_gadget(hsotg, resume);
} else {
/* Change to L0 state */
dwc2_writel(hsotg, GINTSTS_RESETDET, GINTSTS);
/* This event must be used only if controller is suspended */
- if (hsotg->lx_state == DWC2_L2) {
- dwc2_exit_partial_power_down(hsotg, true);
- hsotg->lx_state = DWC2_L0;
- }
+ if (hsotg->in_ppd && hsotg->lx_state == DWC2_L2)
+ dwc2_exit_partial_power_down(hsotg, 0, true);
+
+ hsotg->lx_state = DWC2_L0;
}
if (gintsts & (GINTSTS_USBRST | GINTSTS_RESETDET)) {
spin_lock_irqsave(&hsotg->lock, flags);
/*
- * If controller is hibernated, it must exit from power_down
- * before being initialized / de-initialized
+ * If controller is in partial power down state, it must exit from
+ * that state before being initialized / de-initialized
*/
- if (hsotg->lx_state == DWC2_L2)
- dwc2_exit_partial_power_down(hsotg, false);
+ if (hsotg->lx_state == DWC2_L2 && hsotg->in_ppd)
+ /*
+ * No need to check the return value as
+ * registers are not being restored.
+ */
+ dwc2_exit_partial_power_down(hsotg, 0, false);
if (is_active) {
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
/* Exit partial_power_down */
- ret = dwc2_exit_partial_power_down(hsotg, true);
+ ret = dwc2_exit_partial_power_down(hsotg, 0, true);
if (ret && (ret != -ENOTSUPP))
dev_err(hsotg->dev, "exit partial_power_down failed\n");
} else {
#define GOTGCTL_CHIRPEN BIT(27)
#define GOTGCTL_MULT_VALID_BC_MASK (0x1f << 22)
#define GOTGCTL_MULT_VALID_BC_SHIFT 22
+#define GOTGCTL_CURMODE_HOST BIT(21)
#define GOTGCTL_OTGVER BIT(20)
#define GOTGCTL_BSESVLD BIT(19)
#define GOTGCTL_ASESVLD BIT(18)