On 3/17/2015 2:54 AM, Mian Yousaf Kaukab wrote: > From: Gregory Herrero <gregory.herrero@xxxxxxxxx> > > When suspending usb bus, phy driver may disable controller power. > In this case, registers need to be saved on suspend and restored > on resume. > > Signed-off-by: Gregory Herrero <gregory.herrero@xxxxxxxxx> > --- > drivers/usb/dwc2/core.c | 382 ++++++++++++++++++++++++++++++++++++++++++++++++ > drivers/usb/dwc2/core.h | 84 +++++++++++ > 2 files changed, 466 insertions(+) > > diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c > index d5197d4..bf62d30 100644 > --- a/drivers/usb/dwc2/core.c > +++ b/drivers/usb/dwc2/core.c > @@ -56,6 +56,388 @@ > #include "core.h" > #include "hcd.h" > > +#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) > +/** > + * dwc2_backup_host_registers() - Backup controller host 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 > + */ > +static int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg) > +{ > + struct dwc2_hregs_backup *hr; > + int i; > + > + dev_dbg(hsotg->dev, "%s\n", __func__); > + > + /* Backup Host regs */ > + hr = hsotg->hr_backup; > + if (!hr) { > + hr = kmalloc(sizeof(*hr), GFP_KERNEL); > + if (!hr) { > + dev_err(hsotg->dev, "%s: can't allocate host regs\n", > + __func__); > + return -ENOMEM; > + } > + > + hsotg->hr_backup = hr; > + } > + hr->hcfg = readl(hsotg->regs + HCFG); > + hr->haintmsk = readl(hsotg->regs + HAINTMSK); > + for (i = 0; i < hsotg->core_params->host_channels; ++i) > + hr->hcintmsk[i] = readl(hsotg->regs + HCINTMSK(i)); > + > + hr->hprt0 = readl(hsotg->regs + HPRT0); > + hr->hfir = readl(hsotg->regs + HFIR); > + return 0; > +} > + > +/** > + * dwc2_restore_host_registers() - Restore controller host registers. > + * When resuming usb bus, device registers needs to be restored > + * if controller power were disabled. > + * > + * @hsotg: Programming view of the DWC_otg controller > + */ > +static int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg) > +{ > + struct dwc2_hregs_backup *hr; > + int i; > + > + dev_dbg(hsotg->dev, "%s\n", __func__); > + > + /* Restore host regs */ > + hr = hsotg->hr_backup; > + if (!hr) { > + dev_err(hsotg->dev, "%s: no host registers to restore\n", > + __func__); > + return -EINVAL; > + } > + > + writel(hr->hcfg, hsotg->regs + HCFG); > + writel(hr->haintmsk, hsotg->regs + HAINTMSK); > + > + for (i = 0; i < hsotg->core_params->host_channels; ++i) > + writel(hr->hcintmsk[i], hsotg->regs + HCINTMSK(i)); > + > + writel(hr->hprt0, hsotg->regs + HPRT0); > + writel(hr->hfir, hsotg->regs + HFIR); > + > + kfree(hsotg->hr_backup); Should NULL this out otherwise you will reuse free'd memory. Maybe better, you could just free this on remove. Just reuse the same buffer each time. Same with device/global registers. John -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html