usb: dwc2: Move register save and restore functions
[cascardo/linux.git] / drivers / usb / dwc2 / gadget.c
index 422ab7d..e9940dd 100644 (file)
@@ -3668,3 +3668,105 @@ int dwc2_hsotg_resume(struct dwc2_hsotg *hsotg)
 
        return 0;
 }
+
+/**
+ * dwc2_backup_device_registers() - Backup controller device registers.
+ * When suspending usb bus, registers needs to be backuped
+ * if controller power is disabled once suspended.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ */
+int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
+{
+       struct dwc2_dregs_backup *dr;
+       int i;
+
+       dev_dbg(hsotg->dev, "%s\n", __func__);
+
+       /* Backup dev regs */
+       dr = &hsotg->dr_backup;
+
+       dr->dcfg = dwc2_readl(hsotg->regs + DCFG);
+       dr->dctl = dwc2_readl(hsotg->regs + DCTL);
+       dr->daintmsk = dwc2_readl(hsotg->regs + DAINTMSK);
+       dr->diepmsk = dwc2_readl(hsotg->regs + DIEPMSK);
+       dr->doepmsk = dwc2_readl(hsotg->regs + DOEPMSK);
+
+       for (i = 0; i < hsotg->num_of_eps; i++) {
+               /* Backup IN EPs */
+               dr->diepctl[i] = dwc2_readl(hsotg->regs + DIEPCTL(i));
+
+               /* Ensure DATA PID is correctly configured */
+               if (dr->diepctl[i] & DXEPCTL_DPID)
+                       dr->diepctl[i] |= DXEPCTL_SETD1PID;
+               else
+                       dr->diepctl[i] |= DXEPCTL_SETD0PID;
+
+               dr->dieptsiz[i] = dwc2_readl(hsotg->regs + DIEPTSIZ(i));
+               dr->diepdma[i] = dwc2_readl(hsotg->regs + DIEPDMA(i));
+
+               /* Backup OUT EPs */
+               dr->doepctl[i] = dwc2_readl(hsotg->regs + DOEPCTL(i));
+
+               /* Ensure DATA PID is correctly configured */
+               if (dr->doepctl[i] & DXEPCTL_DPID)
+                       dr->doepctl[i] |= DXEPCTL_SETD1PID;
+               else
+                       dr->doepctl[i] |= DXEPCTL_SETD0PID;
+
+               dr->doeptsiz[i] = dwc2_readl(hsotg->regs + DOEPTSIZ(i));
+               dr->doepdma[i] = dwc2_readl(hsotg->regs + DOEPDMA(i));
+       }
+       dr->valid = true;
+       return 0;
+}
+
+/**
+ * dwc2_restore_device_registers() - Restore controller device registers.
+ * When resuming usb bus, device registers needs to be restored
+ * if controller power were disabled.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ */
+int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
+{
+       struct dwc2_dregs_backup *dr;
+       u32 dctl;
+       int i;
+
+       dev_dbg(hsotg->dev, "%s\n", __func__);
+
+       /* Restore dev regs */
+       dr = &hsotg->dr_backup;
+       if (!dr->valid) {
+               dev_err(hsotg->dev, "%s: no device registers to restore\n",
+                       __func__);
+               return -EINVAL;
+       }
+       dr->valid = false;
+
+       dwc2_writel(dr->dcfg, hsotg->regs + DCFG);
+       dwc2_writel(dr->dctl, hsotg->regs + DCTL);
+       dwc2_writel(dr->daintmsk, hsotg->regs + DAINTMSK);
+       dwc2_writel(dr->diepmsk, hsotg->regs + DIEPMSK);
+       dwc2_writel(dr->doepmsk, hsotg->regs + DOEPMSK);
+
+       for (i = 0; i < hsotg->num_of_eps; i++) {
+               /* Restore IN EPs */
+               dwc2_writel(dr->diepctl[i], hsotg->regs + DIEPCTL(i));
+               dwc2_writel(dr->dieptsiz[i], hsotg->regs + DIEPTSIZ(i));
+               dwc2_writel(dr->diepdma[i], hsotg->regs + DIEPDMA(i));
+
+               /* Restore OUT EPs */
+               dwc2_writel(dr->doepctl[i], hsotg->regs + DOEPCTL(i));
+               dwc2_writel(dr->doeptsiz[i], hsotg->regs + DOEPTSIZ(i));
+               dwc2_writel(dr->doepdma[i], hsotg->regs + DOEPDMA(i));
+       }
+
+       /* Set the Power-On Programming done bit */
+       dctl = dwc2_readl(hsotg->regs + DCTL);
+       dctl |= DCTL_PWRONPRGDONE;
+       dwc2_writel(dctl, hsotg->regs + DCTL);
+
+       return 0;
+}