[PATCH 3/4] usb: dwc3: first part of hibernation support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch modifies the existing driver code to allow hibernation
support to be added by the next patch in the series. This patch by
itself should not change the existing functionality.

This patch adds some new register definitions, exports a few
previously static functions that will be needed by the hibernation
code, adds a couple of new functions, refactors a few existing
functions, and adds some hooks that will be needed. The hooks are
currently all defined to no-ops in the new "hibernate.h".

The second part will add the actual hibernation code, and allow it
to be optionally enabled in the kernel config.

NOTE: This patch renames dwc3-pci.c to dwc3_pci.c and dwc3-omap.c
to dwc3_omap.c. This is necessary because the next patch adds a
new platform-specific file that gets included into the bus glue
module. But if a source file name is the same as the module name,
then Kconfig doesn't allow adding other object files to the module.
Other alternatives would be to change the module name, or to
include the other source files directly into dwc3-pci.c or
dwc3-omap.c.

Signed-off-by: Paul Zimmerman <paulz@xxxxxxxxxxxx>
---
 drivers/usb/dwc3/Makefile                     |    6 +-
 drivers/usb/dwc3/core.c                       |   47 +++-
 drivers/usb/dwc3/core.h                       |  153 ++++++++--
 drivers/usb/dwc3/{dwc3-omap.c => dwc3_omap.c} |    2 +-
 drivers/usb/dwc3/{dwc3-pci.c => dwc3_pci.c}   |   14 +-
 drivers/usb/dwc3/ep0.c                        |    5 +
 drivers/usb/dwc3/gadget.c                     |  402 ++++++++++++++++++++-----
 drivers/usb/dwc3/gadget.h                     |   17 +
 drivers/usb/dwc3/haps_pwrctl.h                |   51 +++
 drivers/usb/dwc3/hibernate.h                  |  126 ++++++++
 10 files changed, 703 insertions(+), 120 deletions(-)

diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 900ae74..e37ecd3 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -26,9 +26,11 @@ endif
 # PCI doesn't provide nops if CONFIG_PCI isn't enabled.
 ##
 
-obj-$(CONFIG_USB_DWC3)		+= dwc3-omap.o
+obj-$(CONFIG_USB_DWC3)			+= dwc3-omap.o
+	dwc3-omap-y			:= dwc3_omap.o
 
 ifneq ($(CONFIG_PCI),)
 	obj-$(CONFIG_USB_DWC3)		+= dwc3-pci.o
-endif
 
+	dwc3-pci-y			:= dwc3_pci.o
+endif
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index f5ffe1c..56f60ef 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -56,6 +56,7 @@
 
 #include "core.h"
 #include "gadget.h"
+#include "hibernate.h"
 #include "io.h"
 
 #include "debug.h"
@@ -256,7 +257,7 @@ static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
  *
  * Returns 0 on success otherwise negative errno.
  */
-static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc)
+int dwc3_event_buffers_setup(struct dwc3 *dwc)
 {
 	struct dwc3_event_buffer	*evt;
 	int				n;
@@ -266,6 +267,7 @@ static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc)
 		dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
 				evt->buf, (unsigned long long) evt->dma,
 				evt->length);
+		evt->lpos = 0;
 
 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
 				lower_32_bits(evt->dma));
@@ -286,6 +288,7 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
 
 	for (n = 0; n < dwc->num_event_buffers; n++) {
 		evt = dwc->ev_buffs[n];
+		evt->lpos = 0;
 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
@@ -306,6 +309,21 @@ static void __devinit dwc3_cache_hwparams(struct dwc3 *dwc)
 	parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
 	parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
 	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
+
+	if (!dwc3_hiber_enabled(dwc) &&
+			DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)
+				== DWC3_GHWPARAMS1_EN_PWROPT_HIB) {
+		/*
+		 * If the core supports hibernation, but the user has
+		 * not enabled it, remove it from the hwparams so we
+		 * won't try to enable it. But do keep clock gating
+		 * enabled.
+		 */
+		parms->hwparams1 &= ~DWC3_GHWPARAMS1_PWROPT_MASK;
+		parms->hwparams1 |=
+			DWC3_GHWPARAMS1_PWROPT(DWC3_GHWPARAMS1_EN_PWROPT_CLK);
+		dev_dbg(dwc->dev, "Hibernation disabled\n");
+	}
 }
 
 /**
@@ -355,8 +373,14 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
 	reg &= ~DWC3_GCTL_DISSCRAMBLE;
 
 	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
+	case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
+		if (dwc3_hiber_enabled(dwc)) {
+			dev_dbg(dwc->dev, "Hibernation enabled\n");
+			reg |= DWC3_GCTL_GBLHIBERNATIONEN;
+		}
 	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
 		reg &= ~DWC3_GCTL_DSBLCLKGTNG;
+		dev_dbg(dwc->dev, "Clock gating enabled\n");
 		break;
 	default:
 		dev_dbg(dwc->dev, "No power optimization available\n");
@@ -373,6 +397,13 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
 
 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 
+	ret = dwc3_alloc_scratchpad_buffers(dwc);
+	if (ret) {
+		dev_err(dwc->dev,
+			"failed to allocate scratchpad buffers\n");
+		goto err0;
+	}
+
 	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
 	if (ret) {
 		dev_err(dwc->dev, "failed to allocate event buffers\n");
@@ -383,14 +414,15 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
 	ret = dwc3_event_buffers_setup(dwc);
 	if (ret) {
 		dev_err(dwc->dev, "failed to setup event buffers\n");
-		goto err1;
+		goto err2;
 	}
 
 	return 0;
 
-err1:
+err2:
 	dwc3_free_event_buffers(dwc);
-
+err1:
+	dwc3_free_scratchpad_buffers(dwc);
 err0:
 	return ret;
 }
@@ -399,6 +431,7 @@ static void dwc3_core_exit(struct dwc3 *dwc)
 {
 	dwc3_event_buffers_cleanup(dwc);
 	dwc3_free_event_buffers(dwc);
+	dwc3_free_scratchpad_buffers(dwc);
 }
 
 #define DWC3_ALIGN_MASK		(16 - 1)
@@ -610,6 +643,12 @@ static struct platform_driver dwc3_driver = {
 	},
 };
 
+/* These get filled in by the bus glue code if hibernation is supported */
+void (*dwc3_power_ctl)(struct dwc3 *dwc, int on);
+EXPORT_SYMBOL_GPL(dwc3_power_ctl);
+int (*dwc3_pme_interrupt)(struct dwc3 *dwc);
+EXPORT_SYMBOL_GPL(dwc3_pme_interrupt);
+
 MODULE_ALIAS("platform:dwc3");
 MODULE_AUTHOR("Felipe Balbi <balbi@xxxxxx>");
 MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 12c1105..aa5ee23 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -65,6 +65,7 @@
 #define DWC3_DEVICE_EVENT_CONNECT_DONE		2
 #define DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE	3
 #define DWC3_DEVICE_EVENT_WAKEUP		4
+#define DWC3_DEVICE_EVENT_HIBER_REQ		5
 #define DWC3_DEVICE_EVENT_EOPF			6
 #define DWC3_DEVICE_EVENT_SOF			7
 #define DWC3_DEVICE_EVENT_ERRATIC_ERROR		9
@@ -159,28 +160,36 @@
 #define DWC3_GCTL_PRTCAP_DEVICE	2
 #define DWC3_GCTL_PRTCAP_OTG	3
 
-#define DWC3_GCTL_CORESOFTRESET	(1 << 11)
-#define DWC3_GCTL_SCALEDOWN(n)	((n) << 4)
-#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3)
-#define DWC3_GCTL_DISSCRAMBLE	(1 << 3)
-#define DWC3_GCTL_DSBLCLKGTNG	(1 << 0)
+#define DWC3_GCTL_CORESOFTRESET		(1 << 11)
+#define DWC3_GCTL_SCALEDOWN(n)		((n) << 4)
+#define DWC3_GCTL_SCALEDOWN_MASK	DWC3_GCTL_SCALEDOWN(3)
+#define DWC3_GCTL_DISSCRAMBLE		(1 << 3)
+#define DWC3_GCTL_GBLHIBERNATIONEN	(1 << 1)
+#define DWC3_GCTL_DSBLCLKGTNG		(1 << 0)
 
 /* Global USB2 PHY Configuration Register */
-#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
-#define DWC3_GUSB2PHYCFG_SUSPHY	(1 << 6)
+#define DWC3_GUSB2PHYCFG_PHYSOFTRST	(1 << 31)
+#define DWC3_GUSB2PHYCFG_SUSPHY		(1 << 6)
 
 /* Global USB3 PIPE Control Register */
-#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
-#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
+#define DWC3_GUSB3PIPECTL_PHYSOFTRST	(1 << 31)
+#define DWC3_GUSB3PIPECTL_SUSPHY	(1 << 17)
 
 /* Global TX Fifo Size Register */
-#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
-#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000)
+#define DWC3_GTXFIFOSIZ_TXFDEF(n)	((n) & 0xffff)
+#define DWC3_GTXFIFOSIZ_TXFSTADDR(n)	((n) & 0xffff0000)
 
 /* Global HWPARAMS1 Register */
 #define DWC3_GHWPARAMS1_EN_PWROPT(n)	(((n) & (3 << 24)) >> 24)
 #define DWC3_GHWPARAMS1_EN_PWROPT_NO	0
 #define DWC3_GHWPARAMS1_EN_PWROPT_CLK	1
+#define DWC3_GHWPARAMS1_EN_PWROPT_HIB	2
+#define DWC3_GHWPARAMS1_PWROPT(n)	((n) << 24)
+#define DWC3_GHWPARAMS1_PWROPT_MASK	DWC3_GHWPARAMS1_PWROPT(3)
+
+/* Global HWPARAMS4 Register */
+#define DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(n)	(((n) & (0x0f << 13)) >> 13)
+#define DWC3_MAX_HIBER_SCRATCHBUFS		15
 
 /* Device Configuration Register */
 #define DWC3_DCFG_DEVADDR(addr)	((addr) << 3)
@@ -193,6 +202,8 @@
 #define DWC3_DCFG_LOWSPEED	(2 << 0)
 #define DWC3_DCFG_FULLSPEED1	(3 << 0)
 
+#define DWC3_DCFG_LPM_CAP	(1 << 22)
+
 /* Device Control Register */
 #define DWC3_DCTL_RUN_STOP	(1 << 31)
 #define DWC3_DCTL_CSFTRST	(1 << 30)
@@ -203,14 +214,20 @@
 
 #define DWC3_DCTL_APPL1RES	(1 << 23)
 
-#define DWC3_DCTL_TRGTULST_MASK	(0x0f << 17)
-#define DWC3_DCTL_TRGTULST(n)	((n) << 17)
-
-#define DWC3_DCTL_TRGTULST_U2	(DWC3_DCTL_TRGTULST(2))
-#define DWC3_DCTL_TRGTULST_U3	(DWC3_DCTL_TRGTULST(3))
-#define DWC3_DCTL_TRGTULST_SS_DIS (DWC3_DCTL_TRGTULST(4))
-#define DWC3_DCTL_TRGTULST_RX_DET (DWC3_DCTL_TRGTULST(5))
-#define DWC3_DCTL_TRGTULST_SS_INACT (DWC3_DCTL_TRGTULST(6))
+/* These apply for core versions 1.87a and earlier */
+#define DWC3_DCTL_TRGTULST_MASK		(0x0f << 17)
+#define DWC3_DCTL_TRGTULST(n)		((n) << 17)
+#define DWC3_DCTL_TRGTULST_U2		(DWC3_DCTL_TRGTULST(2))
+#define DWC3_DCTL_TRGTULST_U3		(DWC3_DCTL_TRGTULST(3))
+#define DWC3_DCTL_TRGTULST_SS_DIS	(DWC3_DCTL_TRGTULST(4))
+#define DWC3_DCTL_TRGTULST_RX_DET	(DWC3_DCTL_TRGTULST(5))
+#define DWC3_DCTL_TRGTULST_SS_INACT	(DWC3_DCTL_TRGTULST(6))
+
+/* These apply for core versions 1.94a and later */
+#define DWC3_DCTL_KEEP_CONNECT	(1 << 19)
+#define DWC3_DCTL_L1_HIBER_EN	(1 << 18)
+#define DWC3_DCTL_CRS		(1 << 17)
+#define DWC3_DCTL_CSS		(1 << 16)
 
 #define DWC3_DCTL_INITU2ENA	(1 << 12)
 #define DWC3_DCTL_ACCEPTU2ENA	(1 << 11)
@@ -236,6 +253,7 @@
 #define DWC3_DEVTEN_ERRTICERREN		(1 << 9)
 #define DWC3_DEVTEN_SOFEN		(1 << 7)
 #define DWC3_DEVTEN_EOPFEN		(1 << 6)
+#define DWC3_DEVTEN_HIBERNATIONREQEVTEN	(1 << 5)
 #define DWC3_DEVTEN_WKUPEVTEN		(1 << 4)
 #define DWC3_DEVTEN_ULSTCNGEN		(1 << 3)
 #define DWC3_DEVTEN_CONNECTDONEEN	(1 << 2)
@@ -243,7 +261,15 @@
 #define DWC3_DEVTEN_DISCONNEVTEN	(1 << 0)
 
 /* Device Status Register */
+#define DWC3_DSTS_DCNRD			(1 << 29)
+
+/* This applies for core versions 1.87a and earlier */
 #define DWC3_DSTS_PWRUPREQ		(1 << 24)
+
+/* These apply for core versions 1.94a and later */
+#define DWC3_DSTS_RSS			(1 << 25)
+#define DWC3_DSTS_SSS			(1 << 24)
+
 #define DWC3_DSTS_COREIDLE		(1 << 23)
 #define DWC3_DSTS_DEVCTRLHLT		(1 << 22)
 
@@ -264,13 +290,31 @@
 #define DWC3_DSTS_FULLSPEED1		(3 << 0)
 
 /* Device Generic Command Register */
-#define DWC3_DGCMD_SET_LMP		0x01
-#define DWC3_DGCMD_SET_PERIODIC_PAR	0x02
-#define DWC3_DGCMD_XMIT_FUNCTION	0x03
-#define DWC3_DGCMD_SELECTED_FIFO_FLUSH	0x09
-#define DWC3_DGCMD_ALL_FIFO_FLUSH	0x0a
-#define DWC3_DGCMD_SET_ENDPOINT_NRDY	0x0c
-#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK	0x10
+#define DWC3_DGCMD_STATUS_MASK		(0x0f << 12)
+#define DWC3_DGCMD_STATUS(x)		(((x) & DWC3_DGCMD_STATUS_MASK) >> 12)
+#define DWC3_DGCMD_CMDACT		(1 << 10)
+#define DWC3_DGCMD_CMDIOC		(1 << 8)
+
+#define DWC3_DGCMD_SET_LMP			0x01
+#define DWC3_DGCMD_SET_PERIODIC_PAR		0x02
+#define DWC3_DGCMD_XMIT_FUNCTION		0x03
+
+/* These apply for core versions 1.94a and later */
+#define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO	0x04
+#define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI	0x05
+
+#define DWC3_DGCMD_SELECTED_FIFO_FLUSH		0x09
+#define DWC3_DGCMD_ALL_FIFO_FLUSH		0x0a
+#define DWC3_DGCMD_SET_ENDPOINT_NRDY		0x0c
+#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK		0x10
+
+/* Device Generic Command Parameter Register */
+#define DWC3_DGCMDPAR_FORCE_LINKPM_ACCEPT	(1 << 0)
+#define DWC3_DGCMDPAR_FIFO_NUM(n)		((n) << 0)
+#define DWC3_DGCMDPAR_RX_FIFO			(0 << 5)
+#define DWC3_DGCMDPAR_TX_FIFO			(1 << 5)
+#define DWC3_DGCMDPAR_LOOPBACK_DIS		(0 << 0)
+#define DWC3_DGCMDPAR_LOOPBACK_ENA		(1 << 0)
 
 /* Device Endpoint Command Register */
 #define DWC3_DEPCMD_PARAM_SHIFT		16
@@ -288,7 +332,10 @@
 #define DWC3_DEPCMD_STARTTRANSFER	(0x06 << 0)
 #define DWC3_DEPCMD_CLEARSTALL		(0x05 << 0)
 #define DWC3_DEPCMD_SETSTALL		(0x04 << 0)
+/* This applies for core versions 1.90a and earlier */
 #define DWC3_DEPCMD_GETSEQNUMBER	(0x03 << 0)
+/* This applies for core versions 1.94a and later */
+#define DWC3_DEPCMD_GETEPSTATE		(0x03 << 0)
 #define DWC3_DEPCMD_SETTRANSFRESOURCE	(0x02 << 0)
 #define DWC3_DEPCMD_SETEPCONFIG		(0x01 << 0)
 
@@ -381,6 +428,11 @@ struct dwc3_ep {
 	u8			type;
 	u8			res_trans_idx;
 	u32			interval;
+	u32			saved_state;
+
+#ifdef CONFIG_USB_DWC3_HIBERNATION
+	int			hiber_trb_idx;
+#endif
 
 	char			name[20];
 
@@ -423,6 +475,8 @@ enum dwc3_link_state {
 	DWC3_LINK_STATE_HRESET		= 0x09,
 	DWC3_LINK_STATE_CMPLY		= 0x0a,
 	DWC3_LINK_STATE_LPBK		= 0x0b,
+	DWC3_LINK_STATE_RESET		= 0x0e,
+	DWC3_LINK_STATE_RESUME		= 0x0f,
 	DWC3_LINK_STATE_MASK		= 0x0f,
 };
 
@@ -472,6 +526,7 @@ struct dwc3_trb {
 #define DWC3_TRB_STS_OKAY			0
 #define DWC3_TRB_STS_MISSED_ISOC		1
 #define DWC3_TRB_STS_SETUP_PENDING		2
+#define DWC3_TRB_STS_XFER_IN_PROG		4
 		};
 		u32 len_pcm;
 	};
@@ -582,6 +637,14 @@ struct dwc3_request {
 	unsigned		queued:1;
 };
 
+/*
+ * struct dwc3_scratchpad_array - hibernation scratchpad array
+ * (format defined by hw)
+ */
+struct dwc3_scratchpad_array {
+	__le64	dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS];
+};
+
 /**
  * struct dwc3 - representation of our controller
  * @ctrl_req: usb control request which is used for ep0
@@ -662,8 +725,10 @@ struct dwc3 {
 #define DWC3_REVISION_180A	0x5533180a
 #define DWC3_REVISION_183A	0x5533183a
 #define DWC3_REVISION_185A	0x5533185a
+#define DWC3_REVISION_187A	0x5533187a
 #define DWC3_REVISION_188A	0x5533188a
 #define DWC3_REVISION_190A	0x5533190a
+#define DWC3_REVISION_194A	0x5533194a
 
 	unsigned		is_selfpowered:1;
 	unsigned		three_stage_setup:1;
@@ -675,6 +740,33 @@ struct dwc3 {
 	unsigned		needs_fifo_resize:1;
 	unsigned		resize_fifos:1;
 
+#ifdef CONFIG_USB_DWC3_HIBERNATION
+	unsigned		hiber_wait_connect:1;
+	unsigned		hiber_wait_u0:1;
+
+	int			hibernate;
+#define DWC3_HIBER_AWAKE	0
+#define DWC3_HIBER_ENTER_NOSAVE	1
+#define DWC3_HIBER_ENTER_SAVE	2
+#define DWC3_HIBER_SLEEPING	3
+#define DWC3_HIBER_WAIT_LINK_UP	4
+#define DWC3_HIBER_SS_DIS_QUIRK	5
+
+	int			pme_ready;
+	int			usage_cnt;
+
+	struct task_struct	*hiber_thread;
+	struct dwc3_scratchpad_array *scratchpad_array;
+	dma_addr_t		scratchpad_array_dma;
+	void			*scratchpad[DWC3_MAX_HIBER_SCRATCHBUFS];
+
+	u32			gctl_save;
+	u32			dcfg_save;
+	u32			dctl_save;
+	u32			rxfifosz_save;
+	u32			txfifosz_save[DWC3_ENDPOINTS_NUM / 2];
+#endif
+
 	enum dwc3_ep0_next	ep0_next_event;
 	enum dwc3_ep0_state	ep0state;
 	enum dwc3_link_state	link_state;
@@ -843,7 +935,12 @@ void dwc3_host_exit(struct dwc3 *dwc);
 int dwc3_gadget_init(struct dwc3 *dwc);
 void dwc3_gadget_exit(struct dwc3 *dwc);
 
-extern int dwc3_get_device_id(void);
-extern void dwc3_put_device_id(int id);
+int dwc3_get_device_id(void);
+void dwc3_put_device_id(int id);
+int dwc3_event_buffers_setup(struct dwc3 *dwc);
+
+/* function pointers for hibernation support */
+extern void (*dwc3_power_ctl)(struct dwc3 *dwc, int on);
+extern int (*dwc3_pme_interrupt)(struct dwc3 *dwc);
 
 #endif /* __DRIVERS_USB_DWC3_CORE_H */
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3_omap.c
similarity index 99%
rename from drivers/usb/dwc3/dwc3-omap.c
rename to drivers/usb/dwc3/dwc3_omap.c
index 64e29c3..c422dfb 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3_omap.c
@@ -1,5 +1,5 @@
 /**
- * dwc3-omap.c - OMAP Specific Glue layer
+ * dwc3_omap.c - OMAP Specific Glue layer
  *
  * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
  *
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3_pci.c
similarity index 94%
rename from drivers/usb/dwc3/dwc3-pci.c
rename to drivers/usb/dwc3/dwc3_pci.c
index 64e1f7c..d630fac 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3_pci.c
@@ -1,5 +1,5 @@
 /**
- * dwc3-pci.c - PCI Specific glue layer
+ * dwc3_pci.c - PCI Specific glue layer
  *
  * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
  *
@@ -43,8 +43,8 @@
 #include <linux/platform_device.h>
 
 #include "core.h"
+#include "haps_pwrctl.h"
 
-/* FIXME define these in <linux/pci_ids.h> */
 #define PCI_VENDOR_ID_SYNOPSYS		0x16c3
 #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3	0xabcd
 
@@ -68,7 +68,7 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,
 		goto err0;
 	}
 
-	glue->dev	= &pci->dev;
+	glue->dev = &pci->dev;
 
 	ret = pci_enable_device(pci);
 	if (ret) {
@@ -106,6 +106,12 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,
 		goto err4;
 	}
 
+	if (pci->vendor == PCI_VENDOR_ID_SYNOPSYS &&
+			pci->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3) {
+		dwc3_power_ctl = dwc3_haps_power_ctl;
+		dwc3_pme_interrupt = dwc3_haps_pme_intr;
+	}
+
 	pci_set_drvdata(pci, glue);
 
 	dma_set_coherent_mask(&dwc3->dev, pci->dev.coherent_dma_mask);
@@ -113,7 +119,7 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,
 	dwc3->dev.dma_mask = pci->dev.dma_mask;
 	dwc3->dev.dma_parms = pci->dev.dma_parms;
 	dwc3->dev.parent = &pci->dev;
-	glue->dwc3	= dwc3;
+	glue->dwc3 = dwc3;
 
 	ret = platform_device_add(dwc3);
 	if (ret) {
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 263c360..1a16678 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -52,6 +52,7 @@
 
 #include "core.h"
 #include "gadget.h"
+#include "hibernate.h"
 #include "io.h"
 
 static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum);
@@ -182,6 +183,9 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
 	int				ret;
 
 	spin_lock_irqsave(&dwc->lock, flags);
+	dwc3_wait_if_hibernating(dwc, flags);
+	dwc3_gadget_get_ctlr(dwc);
+
 	if (!dep->desc) {
 		dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
 				request, dep->name);
@@ -202,6 +206,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
 	ret = __dwc3_gadget_ep0_queue(dep, req);
 
 out:
+	dwc3_gadget_put_ctlr(dwc);
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return ret;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 4702b75..accf876 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -52,6 +52,7 @@
 
 #include "core.h"
 #include "gadget.h"
+#include "hibernate.h"
 #include "io.h"
 
 #define DMA_ADDR_INVALID	(~(dma_addr_t)0)
@@ -90,6 +91,38 @@ int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
 }
 
 /**
+ * dwc3_gadget_get_link_state - Gets current state of USB Link
+ * @dwc: pointer to our context structure
+ * @state: the state to put link into
+ *
+ * Caller should take care of locking. This function will
+ * return current link state on success or -ETIMEDOUT.
+ */
+int dwc3_gadget_get_link_state(struct dwc3 *dwc)
+{
+	int		retries = 10000;
+	u32		reg;
+
+	/*
+	 * Wait until device controller is ready. Only applies to 1.94a and
+	 * later RTL. This will succeed immediately on pre-1.94a because the
+	 * undefined register bits are hardwired to 0.
+	 */
+	while (--retries) {
+		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+		if (reg & DWC3_DSTS_DCNRD)
+			udelay(5);
+		else
+			break;
+	}
+
+	if (retries <= 0)
+		return -ETIMEDOUT;
+
+	return DWC3_DSTS_USBLNKST(reg);
+}
+
+/**
  * dwc3_gadget_set_link_state - Sets USB Link to a particular State
  * @dwc: pointer to our context structure
  * @state: the state to put link into
@@ -102,6 +135,22 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
 	int		retries = 10000;
 	u32		reg;
 
+	/*
+	 * Wait until device controller is ready. Only applies to 1.94a and
+	 * later RTL. This will succeed immediately on pre-1.94a because the
+	 * undefined register bits are hardwired to 0.
+	 */
+	while (--retries) {
+		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+		if (reg & DWC3_DSTS_DCNRD)
+			udelay(5);
+		else
+			break;
+	}
+
+	if (retries <= 0)
+		return -ETIMEDOUT;
+
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 	reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
 
@@ -109,7 +158,11 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
 	reg |= DWC3_DCTL_ULSTCHNGREQ(state);
 	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 
+	if (dwc->revision >= DWC3_REVISION_194A)
+		return 0;
+
 	/* wait for a change in DSTS */
+	retries = 10000;
 	while (--retries) {
 		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
 
@@ -312,8 +365,8 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd)
 		return "Clear Stall";
 	case DWC3_DEPCMD_SETSTALL:
 		return "Set Stall";
-	case DWC3_DEPCMD_GETSEQNUMBER:
-		return "Get Data Sequence Number";
+	case DWC3_DEPCMD_GETEPSTATE:
+		return "Get Endpoint State";
 	case DWC3_DEPCMD_SETTRANSFRESOURCE:
 		return "Set Endpoint Transfer Resource";
 	case DWC3_DEPCMD_SETEPCONFIG:
@@ -360,6 +413,63 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
 	} while (1);
 }
 
+static const char *dwc3_gadget_dev_cmd_string(u8 cmd)
+{
+	switch (cmd) {
+	case DWC3_DGCMD_SET_LMP:
+		return "Transmit Set Link Function LMP";
+	case DWC3_DGCMD_SET_PERIODIC_PAR:
+		return "Set Periodic Parameters";
+	case DWC3_DGCMD_XMIT_FUNCTION:
+		return "Transmit Function Wake Device Notification";
+	case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO:
+		return "Set Scratchpad Buffer Array Address Lo";
+	case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI:
+		return "Set Scratchpad Buffer Array Address Hi";
+	case DWC3_DGCMD_SELECTED_FIFO_FLUSH:
+		return "Selected FIFO Flush";
+	case DWC3_DGCMD_ALL_FIFO_FLUSH:
+		return "All FIFO Flush";
+	case DWC3_DGCMD_SET_ENDPOINT_NRDY:
+		return "Set Endpoint NRDY";
+	case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK:
+		return "Run SoC Bus LoopBack Test";
+	default:
+		return "UNKNOWN command";
+	}
+}
+
+int dwc3_send_gadget_dev_cmd(struct dwc3 *dwc, unsigned cmd, u32 param)
+{
+	u32			timeout = 500;
+	u32			reg;
+
+	dev_vdbg(dwc->dev, "%s: cmd '%s' param %08x\n", __func__,
+			dwc3_gadget_dev_cmd_string(cmd), param);
+
+	dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);
+
+	dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
+	do {
+		reg = dwc3_readl(dwc->regs, DWC3_DGCMD);
+		if (!(reg & DWC3_DGCMD_CMDACT)) {
+			dev_vdbg(dwc->dev, "Command Complete --> %d\n",
+					DWC3_DGCMD_STATUS(reg));
+			return 0;
+		}
+
+		/*
+		 * We can't sleep here, because it is also called from
+		 * interrupt context.
+		 */
+		timeout--;
+		if (!timeout)
+			return -ETIMEDOUT;
+
+		udelay(1);
+	} while (1);
+}
+
 static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
 		struct dwc3_trb_hw *trb)
 {
@@ -426,7 +536,8 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
 
 static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
 		const struct usb_endpoint_descriptor *desc,
-		const struct usb_ss_ep_comp_descriptor *comp_desc)
+		const struct usb_ss_ep_comp_descriptor *comp_desc,
+		bool restore)
 {
 	struct dwc3_gadget_ep_cmd_params params;
 
@@ -468,6 +579,11 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
 		dep->interval = 1 << (desc->bInterval - 1);
 	}
 
+	if (restore) {
+		params.param0 |= DWC3_DEPCFG_ACTION_RESTORE;
+		params.param2 = dep->saved_state;
+	}
+
 	return dwc3_send_gadget_ep_cmd(dwc, dep->number,
 			DWC3_DEPCMD_SETEPCONFIG, &params);
 }
@@ -491,9 +607,10 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)
  *
  * Caller should take care of locking
  */
-static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
+int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
 		const struct usb_endpoint_descriptor *desc,
-		const struct usb_ss_ep_comp_descriptor *comp_desc)
+		const struct usb_ss_ep_comp_descriptor *comp_desc,
+		bool restore)
 {
 	struct dwc3		*dwc = dep->dwc;
 	u32			reg;
@@ -505,7 +622,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
 			return ret;
 	}
 
-	ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc);
+	ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, restore);
 	if (ret)
 		return ret;
 
@@ -546,13 +663,12 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
 	return 0;
 }
 
-static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum);
 static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
 {
 	struct dwc3_request		*req;
 
 	if (!list_empty(&dep->req_queued))
-		dwc3_stop_active_transfer(dwc, dep->number);
+		dwc3_stop_active_transfer(dwc, dep->number, true);
 
 	while (!list_empty(&dep->request_list)) {
 		req = next_request(&dep->request_list);
@@ -651,7 +767,7 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
 	dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
 
 	spin_lock_irqsave(&dwc->lock, flags);
-	ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc);
+	ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false);
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return ret;
@@ -1071,6 +1187,8 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
 	int				ret = 0;
 
 	spin_lock_irqsave(&dwc->lock, flags);
+	dwc3_wait_if_hibernating(dwc, flags);
+	dwc3_gadget_get_ctlr(dwc);
 
 	list_for_each_entry(r, &dep->request_list, list) {
 		if (r == req)
@@ -1084,7 +1202,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
 		}
 		if (r == req) {
 			/* wait until it is processed */
-			dwc3_stop_active_transfer(dwc, dep->number);
+			dwc3_stop_active_transfer(dwc, dep->number, true);
 			goto out0;
 		}
 		dev_err(dwc->dev, "request %p was not queued to %s\n",
@@ -1097,6 +1215,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
 	dwc3_gadget_giveback(dep, req, -ECONNRESET);
 
 out0:
+	dwc3_gadget_put_ctlr(dwc);
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return ret;
@@ -1155,6 +1274,8 @@ static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
 	int				ret;
 
 	spin_lock_irqsave(&dwc->lock, flags);
+	dwc3_wait_if_hibernating(dwc, flags);
+	dwc3_gadget_get_ctlr(dwc);
 
 	if (usb_endpoint_xfer_isoc(dep->desc)) {
 		dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name);
@@ -1164,6 +1285,7 @@ static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
 
 	ret = __dwc3_gadget_ep_set_halt(dep, value);
 out:
+	dwc3_gadget_put_ctlr(dwc);
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return ret;
@@ -1184,7 +1306,7 @@ static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
 
 /* -------------------------------------------------------------------------- */
 
-static struct usb_endpoint_descriptor dwc3_gadget_ep0_desc = {
+struct usb_endpoint_descriptor dwc3_gadget_ep0_desc = {
 	.bLength	= USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType = USB_DT_ENDPOINT,
 	.bmAttributes	= USB_ENDPOINT_XFER_CONTROL,
@@ -1238,6 +1360,8 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
 	u8			speed;
 
 	spin_lock_irqsave(&dwc->lock, flags);
+	dwc3_wait_if_hibernating(dwc, flags);
+	dwc3_gadget_get_ctlr(dwc);
 
 	/*
 	 * According to the Databook Remote wakeup request should
@@ -1273,9 +1397,11 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
 		goto out;
 	}
 
-	/* write zeroes to Link Change Request */
-	reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
-	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+	if (dwc->revision < DWC3_REVISION_194A) {
+		/* write zeroes to Link Change Request */
+		reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
+		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+	}
 
 	/* poll until Link State changes to ON */
 	timeout = jiffies + msecs_to_jiffies(100);
@@ -1298,6 +1424,7 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
 	}
 
 out:
+	dwc3_gadget_put_ctlr(dwc);
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return ret;
@@ -1316,16 +1443,23 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
 	return 0;
 }
 
-static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
+void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
 {
 	u32			reg;
 	u32			timeout = 500;
 
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 	if (is_on) {
-		reg &= ~DWC3_DCTL_TRGTULST_MASK;
-		reg |= (DWC3_DCTL_RUN_STOP
-				| DWC3_DCTL_TRGTULST_RX_DET);
+		if (dwc->revision <= DWC3_REVISION_187A) {
+			reg &= ~DWC3_DCTL_TRGTULST_MASK;
+			reg |= DWC3_DCTL_TRGTULST_RX_DET;
+		}
+		reg |= DWC3_DCTL_RUN_STOP;
+
+		if (dwc3_hiber_enabled(dwc))
+			reg |= DWC3_DCTL_KEEP_CONNECT;
+		else
+			reg &= ~DWC3_DCTL_KEEP_CONNECT;
 	} else {
 		reg &= ~DWC3_DCTL_RUN_STOP;
 	}
@@ -1361,53 +1495,35 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
 	is_on = !!is_on;
 
 	spin_lock_irqsave(&dwc->lock, flags);
+	dwc3_wait_if_hibernating(dwc, flags);
+	dwc3_gadget_get_ctlr(dwc);
+
 	dwc3_gadget_run_stop(dwc, is_on);
+
+	dwc3_gadget_put_ctlr(dwc);
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return 0;
 }
 
-static int dwc3_gadget_start(struct usb_gadget *g,
-		struct usb_gadget_driver *driver)
+int __dwc3_gadget_start(struct dwc3 *dwc, bool restore)
 {
-	struct dwc3		*dwc = gadget_to_dwc(g);
-	struct dwc3_ep		*dep;
-	unsigned long		flags;
-	int			ret = 0;
-	u32			reg;
-
-	spin_lock_irqsave(&dwc->lock, flags);
-
-	if (dwc->gadget_driver) {
-		dev_err(dwc->dev, "%s is already bound to %s\n",
-				dwc->gadget.name,
-				dwc->gadget_driver->driver.name);
-		ret = -EBUSY;
-		goto err0;
-	}
-
-	dwc->gadget_driver	= driver;
-	dwc->gadget.dev.driver	= &driver->driver;
-
-	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
-	reg &= ~(DWC3_DCFG_SPEED_MASK);
-	reg |= dwc->maximum_speed;
-	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+	struct dwc3_ep	*dep;
+	int		ret;
 
 	dwc->start_config_issued = false;
 
-	/* Start with SuperSpeed Default */
-	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
-
 	dep = dwc->eps[0];
-	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL,
+					restore);
 	if (ret) {
 		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
 		goto err0;
 	}
 
 	dep = dwc->eps[1];
-	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL,
+					restore);
 	if (ret) {
 		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
 		goto err1;
@@ -1417,14 +1533,48 @@ static int dwc3_gadget_start(struct usb_gadget *g,
 	dwc->ep0state = EP0_SETUP_PHASE;
 	dwc3_ep0_out_start(dwc);
 
-	spin_unlock_irqrestore(&dwc->lock, flags);
-
 	return 0;
 
 err1:
 	__dwc3_gadget_ep_disable(dwc->eps[0]);
-
 err0:
+	return ret;
+}
+
+static int dwc3_gadget_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	unsigned long		flags;
+	u32			reg;
+	int			ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	dwc3_wait_if_hibernating(dwc, flags);
+	dwc3_gadget_get_ctlr(dwc);
+
+	if (dwc->gadget_driver) {
+		dev_err(dwc->dev, "%s is already bound to %s\n",
+				dwc->gadget.name,
+				dwc->gadget_driver->driver.name);
+		ret = -EBUSY;
+		goto out;
+	}
+
+	dwc->gadget_driver	= driver;
+	dwc->gadget.dev.driver	= &driver->driver;
+
+	/* Start with SuperSpeed Default */
+	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+	reg &= ~(DWC3_DCFG_SPEED_MASK);
+	reg |= dwc->maximum_speed;
+	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+	ret = __dwc3_gadget_start(dwc, false);
+out:
+	dwc3_gadget_put_ctlr(dwc);
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return ret;
@@ -1437,6 +1587,8 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
 	unsigned long		flags;
 
 	spin_lock_irqsave(&dwc->lock, flags);
+	dwc3_wait_if_hibernating(dwc, flags);
+	dwc3_gadget_get_ctlr(dwc);
 
 	__dwc3_gadget_ep_disable(dwc->eps[0]);
 	__dwc3_gadget_ep_disable(dwc->eps[1]);
@@ -1444,10 +1596,12 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
 	dwc->gadget_driver	= NULL;
 	dwc->gadget.dev.driver	= NULL;
 
+	dwc3_gadget_put_ctlr(dwc);
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return 0;
 }
+
 static const struct usb_gadget_ops dwc3_gadget_ops = {
 	.get_frame		= dwc3_gadget_get_frame,
 	.wakeup			= dwc3_gadget_wakeup,
@@ -1794,7 +1948,7 @@ static void dwc3_disconnect_gadget(struct dwc3 *dwc)
 	}
 }
 
-static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
+void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
 {
 	struct dwc3_ep *dep;
 	struct dwc3_gadget_ep_cmd_params params;
@@ -1803,10 +1957,14 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
 
 	dep = dwc->eps[epnum];
 
-	WARN_ON(!dep->res_trans_idx);
-	if (dep->res_trans_idx) {
+	if (epnum != 0)
+		WARN_ON(!dep->res_trans_idx);
+
+	if (dep->res_trans_idx || epnum == 0) {
 		cmd = DWC3_DEPCMD_ENDTRANSFER;
-		cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC;
+		if (force)
+			cmd |= DWC3_DEPCMD_HIPRI_FORCERM;
+		cmd |= DWC3_DEPCMD_CMDIOC;
 		cmd |= DWC3_DEPCMD_PARAM(dep->res_trans_idx);
 		memset(&params, 0, sizeof(params));
 		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
@@ -1875,32 +2033,35 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
 
 	dwc->gadget.speed = USB_SPEED_UNKNOWN;
 	dwc->setup_packet_pending = false;
+
+	/* Tell kernel thread to enter hibernation */
+	dwc3_enter_hiber_nosave(dwc);
 }
 
-static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on)
+static void dwc3_gadget_usb3_ena_phy_susp(struct dwc3 *dwc, int enable)
 {
 	u32			reg;
 
 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
 
-	if (on)
-		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
-	else
+	if (enable)
 		reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+	else
+		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
 
 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
 }
 
-static void dwc3_gadget_usb2_phy_power(struct dwc3 *dwc, int on)
+static void dwc3_gadget_usb2_ena_phy_susp(struct dwc3 *dwc, int enable)
 {
 	u32			reg;
 
 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
 
-	if (on)
-		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
-	else
+	if (enable)
 		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+	else
+		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
 
 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
 }
@@ -1945,9 +2106,12 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
 	/* after reset -> Default State */
 	dwc->dev_state = DWC3_DEFAULT_STATE;
 
-	/* Enable PHYs */
-	dwc3_gadget_usb2_phy_power(dwc, true);
-	dwc3_gadget_usb3_phy_power(dwc, true);
+	/* Recent versions support automatic phy suspend and don't need this */
+	if (dwc->revision < DWC3_REVISION_194A) {
+		/* Enable PHYs */
+		dwc3_gadget_usb2_ena_phy_susp(dwc, false);
+		dwc3_gadget_usb3_ena_phy_susp(dwc, false);
+	}
 
 	if (dwc->gadget.speed != USB_SPEED_UNKNOWN)
 		dwc3_disconnect_gadget(dwc);
@@ -1991,21 +2155,21 @@ static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed)
 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 }
 
-static void dwc3_gadget_disable_phy(struct dwc3 *dwc, u8 speed)
+static void dwc3_gadget_suspend_phy(struct dwc3 *dwc, u8 speed)
 {
 	switch (speed) {
 	case USB_SPEED_SUPER:
-		dwc3_gadget_usb2_phy_power(dwc, false);
+		dwc3_gadget_usb2_ena_phy_susp(dwc, true);
 		break;
 	case USB_SPEED_HIGH:
 	case USB_SPEED_FULL:
 	case USB_SPEED_LOW:
-		dwc3_gadget_usb3_phy_power(dwc, false);
+		dwc3_gadget_usb3_ena_phy_susp(dwc, true);
 		break;
 	}
 }
 
-static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
+void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
 {
 	struct dwc3_gadget_ep_cmd_params params;
 	struct dwc3_ep		*dep;
@@ -2063,18 +2227,21 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
 		break;
 	}
 
-	/* Disable unneded PHY */
-	dwc3_gadget_disable_phy(dwc, dwc->gadget.speed);
+	/* Recent versions support automatic phy suspend and don't need this */
+	if (dwc->revision < DWC3_REVISION_194A) {
+		/* Disable unneeded PHY */
+		dwc3_gadget_suspend_phy(dwc, dwc->gadget.speed);
+	}
 
 	dep = dwc->eps[0];
-	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
 	if (ret) {
 		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
 		return;
 	}
 
 	dep = dwc->eps[1];
-	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
 	if (ret) {
 		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
 		return;
@@ -2087,6 +2254,12 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
 	 *
 	 * In both cases reset values should be sufficient.
 	 */
+
+	/*
+	 * Have now done 'Perform the steps in Section 9.1.3
+	 * "Initialization on Connect Done" in databook'.
+	 */
+	dwc3_exit_hibernation_after_connect(dwc, 0);
 }
 
 static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
@@ -2101,10 +2274,21 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
 	dwc->gadget_driver->resume(&dwc->gadget);
 }
 
+static void dwc3_gadget_hiber_interrupt(struct dwc3 *dwc,
+		unsigned int evtinfo)
+{
+	dev_vdbg(dwc->dev, "%s\n", __func__);
+
+	/* Tell kernel thread to save state and enter hibernation */
+	dwc3_enter_hiber_save(dwc);
+}
+
 static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
 		unsigned int evtinfo)
 {
 	enum dwc3_link_state	next = evtinfo & DWC3_LINK_STATE_MASK;
+	u32			reg;
+	u8			speed;
 
 	/*
 	 * WORKAROUND: DWC3 Revisions <1.83a have an issue which, depending
@@ -2152,6 +2336,13 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
 		}
 	}
 
+	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+	speed = reg & DWC3_DSTS_CONNECTSPD;
+	dwc->speed = speed;
+
+	/* do hibernation remote wake if needed */
+	dwc3_hiber_remote_wake(dwc);
+
 	dwc->link_state = next;
 
 	dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
@@ -2173,6 +2364,9 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
 	case DWC3_DEVICE_EVENT_WAKEUP:
 		dwc3_gadget_wakeup_interrupt(dwc);
 		break;
+	case DWC3_DEVICE_EVENT_HIBER_REQ:
+		dwc3_gadget_hiber_interrupt(dwc, event->event_info);
+		break;
 	case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
 		dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
 		break;
@@ -2253,11 +2447,16 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
 static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
 {
 	struct dwc3			*dwc = _dwc;
+	irqreturn_t			ret;
 	int				i;
-	irqreturn_t			ret = IRQ_NONE;
 
 	spin_lock(&dwc->lock);
 
+	/* If in hibernation, we must not touch the hardware */
+	ret = dwc3_hiber_interrupt_hook(dwc);
+	if (ret != IRQ_NONE)
+		goto out;
+
 	for (i = 0; i < dwc->num_event_buffers; i++) {
 		irqreturn_t status;
 
@@ -2265,7 +2464,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
 		if (status == IRQ_HANDLED)
 			ret = status;
 	}
-
+out:
 	spin_unlock(&dwc->lock);
 
 	return ret;
@@ -2351,7 +2550,7 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
 	}
 
 	/* Enable all but Start and End of Frame IRQs */
-	reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
+	reg = DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
 			DWC3_DEVTEN_EVNTOVERFLOWEN |
 			DWC3_DEVTEN_CMDCMPLTEN |
 			DWC3_DEVTEN_ERRTICERREN |
@@ -2359,27 +2558,65 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
 			DWC3_DEVTEN_ULSTCNGEN |
 			DWC3_DEVTEN_CONNECTDONEEN |
 			DWC3_DEVTEN_USBRSTEN |
-			DWC3_DEVTEN_DISCONNEVTEN);
+			DWC3_DEVTEN_DISCONNEVTEN;
+
+	if (dwc3_hiber_enabled(dwc))
+		reg |= DWC3_DEVTEN_HIBERNATIONREQEVTEN;
+
 	dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
 
+	/* Reset device address to zero */
+	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+	reg &= ~DWC3_DCFG_DEVADDR_MASK;
+
+	/* Enable USB2 LPM only on recent versions */
+	if (dwc->revision >= DWC3_REVISION_194A)
+		reg |= DWC3_DCFG_LPM_CAP;
+
+	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+	/* Enable USB2 LPM and automatic phy suspend only on recent versions */
+	if (dwc->revision >= DWC3_REVISION_194A) {
+		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+		reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN);
+		/* TODO: This should be configurable */
+		reg |= DWC3_DCTL_HIRD_THRES(31);
+
+		if (dwc3_hiber_enabled(dwc))
+			reg |= DWC3_DCTL_L1_HIBER_EN;
+
+		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+		dwc3_gadget_usb2_ena_phy_susp(dwc, true);
+		dwc3_gadget_usb3_ena_phy_susp(dwc, true);
+	}
+
+	ret = dwc3_hibernation_init(dwc);
+	if (ret) {
+		dev_err(dwc->dev, "failed to init hibernation\n");
+		goto err6;
+	}
+
 	ret = device_register(&dwc->gadget.dev);
 	if (ret) {
 		dev_err(dwc->dev, "failed to register gadget device\n");
 		put_device(&dwc->gadget.dev);
-		goto err6;
+		goto err7;
 	}
 
 	ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
 	if (ret) {
 		dev_err(dwc->dev, "failed to register udc\n");
-		goto err7;
+		goto err8;
 	}
 
 	return 0;
 
-err7:
+err8:
 	device_unregister(&dwc->gadget.dev);
 
+err7:
+	dwc3_hibernation_exit(dwc);
+
 err6:
 	dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
 	free_irq(irq, dwc);
@@ -2412,6 +2649,9 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
 	int			irq;
 
 	usb_del_gadget_udc(&dwc->gadget);
+
+	dwc3_hibernation_exit(dwc);
+
 	irq = platform_get_irq(to_platform_device(dwc->dev), 0);
 
 	dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index 152b6de..a11b054 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -66,7 +66,12 @@ struct dwc3;
 #define DWC3_DEPCFG_FIFO_NUMBER(n)	((n) << 17)
 #define DWC3_DEPCFG_BURST_SIZE(n)	((n) << 22)
 #define DWC3_DEPCFG_DATA_SEQ_NUM(n)	((n) << 26)
+/* This applies for core versions earlier than 1.94a */
 #define DWC3_DEPCFG_IGN_SEQ_NUM		(1 << 31)
+/* These apply for core versions 1.94a and later */
+#define DWC3_DEPCFG_ACTION_INIT		(0 << 30)
+#define DWC3_DEPCFG_ACTION_RESTORE	(1 << 30)
+#define DWC3_DEPCFG_ACTION_MODIFY	(2 << 30)
 
 /* DEPXFERCFG parameter 0 */
 #define DWC3_DEPXFERCFG_NUM_XFER_RES(n)	((n) & 0xffff)
@@ -101,6 +106,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
 		int status);
 
 int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode);
+int dwc3_gadget_get_link_state(struct dwc3 *dwc);
 int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state);
 
 void dwc3_ep0_interrupt(struct dwc3 *dwc,
@@ -108,11 +114,22 @@ void dwc3_ep0_interrupt(struct dwc3 *dwc,
 void dwc3_ep0_out_start(struct dwc3 *dwc);
 int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
 		gfp_t gfp_flags);
+int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
+		const struct usb_endpoint_descriptor *desc,
+		const struct usb_ss_ep_comp_descriptor *comp_desc,
+		bool restore);
 int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
 int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
 		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
+int dwc3_send_gadget_dev_cmd(struct dwc3 *dwc, unsigned cmd, u32 param);
 void dwc3_map_buffer_to_dma(struct dwc3_request *req);
 void dwc3_unmap_buffer_from_dma(struct dwc3_request *req);
+void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on);
+int __dwc3_gadget_start(struct dwc3 *dwc, bool restore);
+void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force);
+void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc);
+
+extern struct usb_endpoint_descriptor dwc3_gadget_ep0_desc;
 
 /**
  * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
diff --git a/drivers/usb/dwc3/haps_pwrctl.h b/drivers/usb/dwc3/haps_pwrctl.h
new file mode 100644
index 0000000..b82d356
--- /dev/null
+++ b/drivers/usb/dwc3/haps_pwrctl.h
@@ -0,0 +1,51 @@
+/**
+ * haps_pwrctl.h - DesignWare USB3 DRD Controller Power Control for HAPS Header
+ *
+ * Copyright (C) 2011-2012 Synopsys Incorporated
+ *
+ * Author: Paul Zimmerman <paulz@xxxxxxxxxxxx>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+
+#ifdef CONFIG_USB_DWC3_HIBERNATION
+
+void dwc3_haps_power_ctl(struct dwc3 *dwc, int on);
+int dwc3_haps_pme_intr(struct dwc3 *dwc);
+
+#else
+
+static inline void dwc3_haps_power_ctl(struct dwc3 *dwc3, int on) {}
+static inline int dwc3_haps_pme_intr(struct dwc3 *dwc)
+	{ return -1; }
+
+#endif
diff --git a/drivers/usb/dwc3/hibernate.h b/drivers/usb/dwc3/hibernate.h
new file mode 100644
index 0000000..e90567b
--- /dev/null
+++ b/drivers/usb/dwc3/hibernate.h
@@ -0,0 +1,126 @@
+/**
+ * hibernate.h - DesignWare USB3 DRD Controller Hibernation Support Header
+ *
+ * Copyright (C) 2011-2012 Synopsys Incorporated
+ *
+ * Author: Paul Zimmerman <paulz@xxxxxxxxxxxx>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DRIVERS_USB_DWC3_HIBERNATE_H
+#define __DRIVERS_USB_DWC3_HIBERNATE_H
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/kthread.h>
+
+#ifdef CONFIG_USB_DWC3_HIBERNATION
+
+static inline bool dwc3_hiber_enabled(struct dwc3 *dwc)
+{
+	return DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1) ==
+		DWC3_GHWPARAMS1_EN_PWROPT_HIB;
+}
+
+static inline bool dwc3_in_hibernation(struct dwc3 *dwc)
+{
+	return dwc->hibernate >= DWC3_HIBER_SLEEPING &&
+		dwc->hibernate != DWC3_HIBER_SS_DIS_QUIRK;
+}
+
+static inline void dwc3_enter_hiber_nosave(struct dwc3 *dwc)
+{
+	if (dwc3_hiber_enabled(dwc))
+		dwc->hibernate = DWC3_HIBER_ENTER_NOSAVE;
+}
+
+static inline void dwc3_enter_hiber_save(struct dwc3 *dwc)
+{
+	if (dwc3_hiber_enabled(dwc))
+		dwc->hibernate = DWC3_HIBER_ENTER_SAVE;
+}
+
+static inline void dwc3_gadget_get_ctlr(struct dwc3 *dwc)
+{
+	dwc->usage_cnt++;
+}
+
+static inline void dwc3_gadget_put_ctlr(struct dwc3 *dwc)
+{
+	dwc->usage_cnt--;
+}
+
+#define dwc3_wait_if_hibernating(_dwc, _flags)				\
+{									\
+	int _temp = (_dwc)->hibernate;					\
+	while (_temp >= DWC3_HIBER_SLEEPING &&				\
+			_temp != DWC3_HIBER_SS_DIS_QUIRK) {		\
+		spin_unlock_irqrestore(&(_dwc)->lock, (_flags));	\
+		msleep(1);						\
+		spin_lock_irqsave(&(_dwc)->lock, (_flags));		\
+		_temp = (_dwc)->hibernate;				\
+	}								\
+}
+
+int dwc3_hibernation_init(struct dwc3 *dwc);
+void dwc3_hibernation_exit(struct dwc3 *dwc);
+irqreturn_t dwc3_hiber_interrupt_hook(struct dwc3 *dwc);
+int dwc3_alloc_scratchpad_buffers(struct dwc3 *dwc);
+void dwc3_free_scratchpad_buffers(struct dwc3 *dwc);
+void dwc3_hiber_remote_wake(struct dwc3 *dwc);
+void dwc3_enter_hibernation(struct dwc3 *dwc, bool save_state);
+void dwc3_exit_hibernation_after_connect(struct dwc3 *dwc, bool connected);
+
+#else
+
+static inline bool dwc3_hiber_enabled(struct dwc3 *d)	{ return false; }
+static inline bool dwc3_in_hibernation(struct dwc3 *d)	{ return false; }
+static inline void dwc3_enter_hiber_nosave(struct dwc3 *d)		{}
+static inline void dwc3_enter_hiber_save(struct dwc3 *d)		{}
+static inline void dwc3_gadget_get_ctlr(struct dwc3 *d)			{}
+static inline void dwc3_gadget_put_ctlr(struct dwc3 *d)			{}
+static inline void dwc3_wait_if_hibernating(struct dwc3 *d, unsigned long f)
+	{}
+
+static inline int dwc3_hibernation_init(struct dwc3 *dwc)	{ return 0; }
+static inline void dwc3_hibernation_exit(struct dwc3 *dwc)		{}
+static inline irqreturn_t dwc3_hiber_interrupt_hook(struct dwc3 *d)
+	{ return IRQ_NONE; }
+static inline int dwc3_alloc_scratchpad_buffers(struct dwc3 *d)	{ return 0; }
+static inline void dwc3_free_scratchpad_buffers(struct dwc3 *d)		{}
+static inline void dwc3_hiber_remote_wake(struct dwc3 *d)		{}
+static inline void dwc3_enter_hibernation(struct dwc3 *d, bool s)	{}
+static inline void dwc3_exit_hibernation_after_connect(struct dwc3 *d, bool c)
+	{}
+
+#endif
+#endif /* __DRIVERS_USB_DWC3_HIBERNATE_H */
-- 
1.7.4.4

--
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


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux