xref: /openbmc/linux/drivers/usb/dwc3/core.c (revision 9d6173e1)
172246da4SFelipe Balbi /**
272246da4SFelipe Balbi  * core.c - DesignWare USB3 DRD Controller Core file
372246da4SFelipe Balbi  *
472246da4SFelipe Balbi  * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
572246da4SFelipe Balbi  *
672246da4SFelipe Balbi  * Authors: Felipe Balbi <balbi@ti.com>,
772246da4SFelipe Balbi  *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
872246da4SFelipe Balbi  *
95945f789SFelipe Balbi  * This program is free software: you can redistribute it and/or modify
105945f789SFelipe Balbi  * it under the terms of the GNU General Public License version 2  of
115945f789SFelipe Balbi  * the License as published by the Free Software Foundation.
1272246da4SFelipe Balbi  *
135945f789SFelipe Balbi  * This program is distributed in the hope that it will be useful,
145945f789SFelipe Balbi  * but WITHOUT ANY WARRANTY; without even the implied warranty of
155945f789SFelipe Balbi  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
165945f789SFelipe Balbi  * GNU General Public License for more details.
1772246da4SFelipe Balbi  *
185945f789SFelipe Balbi  * You should have received a copy of the GNU General Public License
195945f789SFelipe Balbi  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
2072246da4SFelipe Balbi  */
2172246da4SFelipe Balbi 
22fa0ea13eSFelipe Balbi #include <linux/version.h>
23a72e658bSFelipe Balbi #include <linux/module.h>
2472246da4SFelipe Balbi #include <linux/kernel.h>
2572246da4SFelipe Balbi #include <linux/slab.h>
2672246da4SFelipe Balbi #include <linux/spinlock.h>
2772246da4SFelipe Balbi #include <linux/platform_device.h>
2872246da4SFelipe Balbi #include <linux/pm_runtime.h>
2972246da4SFelipe Balbi #include <linux/interrupt.h>
3072246da4SFelipe Balbi #include <linux/ioport.h>
3172246da4SFelipe Balbi #include <linux/io.h>
3272246da4SFelipe Balbi #include <linux/list.h>
3372246da4SFelipe Balbi #include <linux/delay.h>
3472246da4SFelipe Balbi #include <linux/dma-mapping.h>
35457e84b6SFelipe Balbi #include <linux/of.h>
36404905a6SHeikki Krogerus #include <linux/acpi.h>
376344475fSSekhar Nori #include <linux/pinctrl/consumer.h>
3872246da4SFelipe Balbi 
3972246da4SFelipe Balbi #include <linux/usb/ch9.h>
4072246da4SFelipe Balbi #include <linux/usb/gadget.h>
41f7e846f0SFelipe Balbi #include <linux/usb/of.h>
42a45c82b8SRuchika Kharwar #include <linux/usb/otg.h>
4372246da4SFelipe Balbi 
4472246da4SFelipe Balbi #include "core.h"
4572246da4SFelipe Balbi #include "gadget.h"
4672246da4SFelipe Balbi #include "io.h"
4772246da4SFelipe Balbi 
4872246da4SFelipe Balbi #include "debug.h"
4972246da4SFelipe Balbi 
50fc8bb91bSFelipe Balbi #define DWC3_DEFAULT_AUTOSUSPEND_DELAY	5000 /* ms */
518300dd23SFelipe Balbi 
529d6173e1SThinh Nguyen /**
539d6173e1SThinh Nguyen  * dwc3_get_dr_mode - Validates and sets dr_mode
549d6173e1SThinh Nguyen  * @dwc: pointer to our context structure
559d6173e1SThinh Nguyen  */
569d6173e1SThinh Nguyen static int dwc3_get_dr_mode(struct dwc3 *dwc)
579d6173e1SThinh Nguyen {
589d6173e1SThinh Nguyen 	enum usb_dr_mode mode;
599d6173e1SThinh Nguyen 	struct device *dev = dwc->dev;
609d6173e1SThinh Nguyen 	unsigned int hw_mode;
619d6173e1SThinh Nguyen 
629d6173e1SThinh Nguyen 	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
639d6173e1SThinh Nguyen 		dwc->dr_mode = USB_DR_MODE_OTG;
649d6173e1SThinh Nguyen 
659d6173e1SThinh Nguyen 	mode = dwc->dr_mode;
669d6173e1SThinh Nguyen 	hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
679d6173e1SThinh Nguyen 
689d6173e1SThinh Nguyen 	switch (hw_mode) {
699d6173e1SThinh Nguyen 	case DWC3_GHWPARAMS0_MODE_GADGET:
709d6173e1SThinh Nguyen 		if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) {
719d6173e1SThinh Nguyen 			dev_err(dev,
729d6173e1SThinh Nguyen 				"Controller does not support host mode.\n");
739d6173e1SThinh Nguyen 			return -EINVAL;
749d6173e1SThinh Nguyen 		}
759d6173e1SThinh Nguyen 		mode = USB_DR_MODE_PERIPHERAL;
769d6173e1SThinh Nguyen 		break;
779d6173e1SThinh Nguyen 	case DWC3_GHWPARAMS0_MODE_HOST:
789d6173e1SThinh Nguyen 		if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) {
799d6173e1SThinh Nguyen 			dev_err(dev,
809d6173e1SThinh Nguyen 				"Controller does not support device mode.\n");
819d6173e1SThinh Nguyen 			return -EINVAL;
829d6173e1SThinh Nguyen 		}
839d6173e1SThinh Nguyen 		mode = USB_DR_MODE_HOST;
849d6173e1SThinh Nguyen 		break;
859d6173e1SThinh Nguyen 	default:
869d6173e1SThinh Nguyen 		if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
879d6173e1SThinh Nguyen 			mode = USB_DR_MODE_HOST;
889d6173e1SThinh Nguyen 		else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
899d6173e1SThinh Nguyen 			mode = USB_DR_MODE_PERIPHERAL;
909d6173e1SThinh Nguyen 	}
919d6173e1SThinh Nguyen 
929d6173e1SThinh Nguyen 	if (mode != dwc->dr_mode) {
939d6173e1SThinh Nguyen 		dev_warn(dev,
949d6173e1SThinh Nguyen 			 "Configuration mismatch. dr_mode forced to %s\n",
959d6173e1SThinh Nguyen 			 mode == USB_DR_MODE_HOST ? "host" : "gadget");
969d6173e1SThinh Nguyen 
979d6173e1SThinh Nguyen 		dwc->dr_mode = mode;
989d6173e1SThinh Nguyen 	}
999d6173e1SThinh Nguyen 
1009d6173e1SThinh Nguyen 	return 0;
1019d6173e1SThinh Nguyen }
1029d6173e1SThinh Nguyen 
1033140e8cbSSebastian Andrzej Siewior void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
1043140e8cbSSebastian Andrzej Siewior {
1053140e8cbSSebastian Andrzej Siewior 	u32 reg;
1063140e8cbSSebastian Andrzej Siewior 
1073140e8cbSSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
1083140e8cbSSebastian Andrzej Siewior 	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
1093140e8cbSSebastian Andrzej Siewior 	reg |= DWC3_GCTL_PRTCAPDIR(mode);
1103140e8cbSSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
1113140e8cbSSebastian Andrzej Siewior }
1128300dd23SFelipe Balbi 
113cf6d867dSFelipe Balbi u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
114cf6d867dSFelipe Balbi {
115cf6d867dSFelipe Balbi 	struct dwc3		*dwc = dep->dwc;
116cf6d867dSFelipe Balbi 	u32			reg;
117cf6d867dSFelipe Balbi 
118cf6d867dSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GDBGFIFOSPACE,
119cf6d867dSFelipe Balbi 			DWC3_GDBGFIFOSPACE_NUM(dep->number) |
120cf6d867dSFelipe Balbi 			DWC3_GDBGFIFOSPACE_TYPE(type));
121cf6d867dSFelipe Balbi 
122cf6d867dSFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GDBGFIFOSPACE);
123cf6d867dSFelipe Balbi 
124cf6d867dSFelipe Balbi 	return DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(reg);
125cf6d867dSFelipe Balbi }
126cf6d867dSFelipe Balbi 
12772246da4SFelipe Balbi /**
12872246da4SFelipe Balbi  * dwc3_core_soft_reset - Issues core soft reset and PHY reset
12972246da4SFelipe Balbi  * @dwc: pointer to our context structure
13072246da4SFelipe Balbi  */
13157303488SKishon Vijay Abraham I static int dwc3_core_soft_reset(struct dwc3 *dwc)
13272246da4SFelipe Balbi {
13372246da4SFelipe Balbi 	u32		reg;
134f59dcab1SFelipe Balbi 	int		retries = 1000;
13557303488SKishon Vijay Abraham I 	int		ret;
13672246da4SFelipe Balbi 
13751e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb2_phy);
13851e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb3_phy);
13957303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb2_generic_phy);
14057303488SKishon Vijay Abraham I 	if (ret < 0)
14157303488SKishon Vijay Abraham I 		return ret;
14257303488SKishon Vijay Abraham I 
14357303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb3_generic_phy);
14457303488SKishon Vijay Abraham I 	if (ret < 0) {
14557303488SKishon Vijay Abraham I 		phy_exit(dwc->usb2_generic_phy);
14657303488SKishon Vijay Abraham I 		return ret;
14757303488SKishon Vijay Abraham I 	}
14872246da4SFelipe Balbi 
149f59dcab1SFelipe Balbi 	/*
150f59dcab1SFelipe Balbi 	 * We're resetting only the device side because, if we're in host mode,
151f59dcab1SFelipe Balbi 	 * XHCI driver will reset the host block. If dwc3 was configured for
152f59dcab1SFelipe Balbi 	 * host-only mode, then we can return early.
153f59dcab1SFelipe Balbi 	 */
154f59dcab1SFelipe Balbi 	if (dwc->dr_mode == USB_DR_MODE_HOST)
15557303488SKishon Vijay Abraham I 		return 0;
156f59dcab1SFelipe Balbi 
157f59dcab1SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
158f59dcab1SFelipe Balbi 	reg |= DWC3_DCTL_CSFTRST;
159f59dcab1SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
160f59dcab1SFelipe Balbi 
161f59dcab1SFelipe Balbi 	do {
162f59dcab1SFelipe Balbi 		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
163f59dcab1SFelipe Balbi 		if (!(reg & DWC3_DCTL_CSFTRST))
164f59dcab1SFelipe Balbi 			return 0;
165f59dcab1SFelipe Balbi 
166f59dcab1SFelipe Balbi 		udelay(1);
167f59dcab1SFelipe Balbi 	} while (--retries);
168f59dcab1SFelipe Balbi 
169f59dcab1SFelipe Balbi 	return -ETIMEDOUT;
17072246da4SFelipe Balbi }
17172246da4SFelipe Balbi 
17272246da4SFelipe Balbi /**
173c5cc74e8SHeikki Krogerus  * dwc3_soft_reset - Issue soft reset
174c5cc74e8SHeikki Krogerus  * @dwc: Pointer to our controller context structure
175c5cc74e8SHeikki Krogerus  */
176c5cc74e8SHeikki Krogerus static int dwc3_soft_reset(struct dwc3 *dwc)
177c5cc74e8SHeikki Krogerus {
178c5cc74e8SHeikki Krogerus 	unsigned long timeout;
179c5cc74e8SHeikki Krogerus 	u32 reg;
180c5cc74e8SHeikki Krogerus 
181c5cc74e8SHeikki Krogerus 	timeout = jiffies + msecs_to_jiffies(500);
182c5cc74e8SHeikki Krogerus 	dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
183c5cc74e8SHeikki Krogerus 	do {
184c5cc74e8SHeikki Krogerus 		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
185c5cc74e8SHeikki Krogerus 		if (!(reg & DWC3_DCTL_CSFTRST))
186c5cc74e8SHeikki Krogerus 			break;
187c5cc74e8SHeikki Krogerus 
188c5cc74e8SHeikki Krogerus 		if (time_after(jiffies, timeout)) {
189c5cc74e8SHeikki Krogerus 			dev_err(dwc->dev, "Reset Timed Out\n");
190c5cc74e8SHeikki Krogerus 			return -ETIMEDOUT;
191c5cc74e8SHeikki Krogerus 		}
192c5cc74e8SHeikki Krogerus 
193c5cc74e8SHeikki Krogerus 		cpu_relax();
194c5cc74e8SHeikki Krogerus 	} while (true);
195c5cc74e8SHeikki Krogerus 
196c5cc74e8SHeikki Krogerus 	return 0;
197c5cc74e8SHeikki Krogerus }
198c5cc74e8SHeikki Krogerus 
199db2be4e9SNikhil Badola /*
200db2be4e9SNikhil Badola  * dwc3_frame_length_adjustment - Adjusts frame length if required
201db2be4e9SNikhil Badola  * @dwc3: Pointer to our controller context structure
202db2be4e9SNikhil Badola  */
203bcdb3272SFelipe Balbi static void dwc3_frame_length_adjustment(struct dwc3 *dwc)
204db2be4e9SNikhil Badola {
205db2be4e9SNikhil Badola 	u32 reg;
206db2be4e9SNikhil Badola 	u32 dft;
207db2be4e9SNikhil Badola 
208db2be4e9SNikhil Badola 	if (dwc->revision < DWC3_REVISION_250A)
209db2be4e9SNikhil Badola 		return;
210db2be4e9SNikhil Badola 
211bcdb3272SFelipe Balbi 	if (dwc->fladj == 0)
212db2be4e9SNikhil Badola 		return;
213db2be4e9SNikhil Badola 
214db2be4e9SNikhil Badola 	reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
215db2be4e9SNikhil Badola 	dft = reg & DWC3_GFLADJ_30MHZ_MASK;
216bcdb3272SFelipe Balbi 	if (!dev_WARN_ONCE(dwc->dev, dft == dwc->fladj,
217db2be4e9SNikhil Badola 	    "request value same as default, ignoring\n")) {
218db2be4e9SNikhil Badola 		reg &= ~DWC3_GFLADJ_30MHZ_MASK;
219bcdb3272SFelipe Balbi 		reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj;
220db2be4e9SNikhil Badola 		dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
221db2be4e9SNikhil Badola 	}
222db2be4e9SNikhil Badola }
223db2be4e9SNikhil Badola 
224c5cc74e8SHeikki Krogerus /**
22572246da4SFelipe Balbi  * dwc3_free_one_event_buffer - Frees one event buffer
22672246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
22772246da4SFelipe Balbi  * @evt: Pointer to event buffer to be freed
22872246da4SFelipe Balbi  */
22972246da4SFelipe Balbi static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
23072246da4SFelipe Balbi 		struct dwc3_event_buffer *evt)
23172246da4SFelipe Balbi {
23272246da4SFelipe Balbi 	dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
23372246da4SFelipe Balbi }
23472246da4SFelipe Balbi 
23572246da4SFelipe Balbi /**
2361d046793SPaul Zimmerman  * dwc3_alloc_one_event_buffer - Allocates one event buffer structure
23772246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
23872246da4SFelipe Balbi  * @length: size of the event buffer
23972246da4SFelipe Balbi  *
2401d046793SPaul Zimmerman  * Returns a pointer to the allocated event buffer structure on success
24172246da4SFelipe Balbi  * otherwise ERR_PTR(errno).
24272246da4SFelipe Balbi  */
24367d0b500SFelipe Balbi static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
24467d0b500SFelipe Balbi 		unsigned length)
24572246da4SFelipe Balbi {
24672246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
24772246da4SFelipe Balbi 
248380f0d28SFelipe Balbi 	evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL);
24972246da4SFelipe Balbi 	if (!evt)
25072246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
25172246da4SFelipe Balbi 
25272246da4SFelipe Balbi 	evt->dwc	= dwc;
25372246da4SFelipe Balbi 	evt->length	= length;
25472246da4SFelipe Balbi 	evt->buf	= dma_alloc_coherent(dwc->dev, length,
25572246da4SFelipe Balbi 			&evt->dma, GFP_KERNEL);
256e32672f0SFelipe Balbi 	if (!evt->buf)
25772246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
25872246da4SFelipe Balbi 
25972246da4SFelipe Balbi 	return evt;
26072246da4SFelipe Balbi }
26172246da4SFelipe Balbi 
26272246da4SFelipe Balbi /**
26372246da4SFelipe Balbi  * dwc3_free_event_buffers - frees all allocated event buffers
26472246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
26572246da4SFelipe Balbi  */
26672246da4SFelipe Balbi static void dwc3_free_event_buffers(struct dwc3 *dwc)
26772246da4SFelipe Balbi {
26872246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
26972246da4SFelipe Balbi 
270696c8b12SFelipe Balbi 	evt = dwc->ev_buf;
27164b6c8a7SAnton Tikhomirov 	if (evt)
27272246da4SFelipe Balbi 		dwc3_free_one_event_buffer(dwc, evt);
27372246da4SFelipe Balbi }
27472246da4SFelipe Balbi 
27572246da4SFelipe Balbi /**
27672246da4SFelipe Balbi  * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
2771d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
27872246da4SFelipe Balbi  * @length: size of event buffer
27972246da4SFelipe Balbi  *
2801d046793SPaul Zimmerman  * Returns 0 on success otherwise negative errno. In the error case, dwc
28172246da4SFelipe Balbi  * may contain some buffers allocated but not all which were requested.
28272246da4SFelipe Balbi  */
28341ac7b3aSBill Pemberton static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
28472246da4SFelipe Balbi {
28572246da4SFelipe Balbi 	struct dwc3_event_buffer *evt;
28672246da4SFelipe Balbi 
28772246da4SFelipe Balbi 	evt = dwc3_alloc_one_event_buffer(dwc, length);
28872246da4SFelipe Balbi 	if (IS_ERR(evt)) {
28972246da4SFelipe Balbi 		dev_err(dwc->dev, "can't allocate event buffer\n");
29072246da4SFelipe Balbi 		return PTR_ERR(evt);
29172246da4SFelipe Balbi 	}
292696c8b12SFelipe Balbi 	dwc->ev_buf = evt;
29372246da4SFelipe Balbi 
29472246da4SFelipe Balbi 	return 0;
29572246da4SFelipe Balbi }
29672246da4SFelipe Balbi 
29772246da4SFelipe Balbi /**
29872246da4SFelipe Balbi  * dwc3_event_buffers_setup - setup our allocated event buffers
2991d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
30072246da4SFelipe Balbi  *
30172246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
30272246da4SFelipe Balbi  */
3037acd85e0SPaul Zimmerman static int dwc3_event_buffers_setup(struct dwc3 *dwc)
30472246da4SFelipe Balbi {
30572246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
30672246da4SFelipe Balbi 
307696c8b12SFelipe Balbi 	evt = dwc->ev_buf;
3081407bf13SFelipe Balbi 	dwc3_trace(trace_dwc3_core,
3091407bf13SFelipe Balbi 			"Event buf %p dma %08llx length %d\n",
31072246da4SFelipe Balbi 			evt->buf, (unsigned long long) evt->dma,
31172246da4SFelipe Balbi 			evt->length);
31272246da4SFelipe Balbi 
3137acd85e0SPaul Zimmerman 	evt->lpos = 0;
3147acd85e0SPaul Zimmerman 
315660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0),
31672246da4SFelipe Balbi 			lower_32_bits(evt->dma));
317660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0),
31872246da4SFelipe Balbi 			upper_32_bits(evt->dma));
319660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
32068d6a01bSFelipe Balbi 			DWC3_GEVNTSIZ_SIZE(evt->length));
321660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
32272246da4SFelipe Balbi 
32372246da4SFelipe Balbi 	return 0;
32472246da4SFelipe Balbi }
32572246da4SFelipe Balbi 
32672246da4SFelipe Balbi static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
32772246da4SFelipe Balbi {
32872246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
32972246da4SFelipe Balbi 
330696c8b12SFelipe Balbi 	evt = dwc->ev_buf;
3317acd85e0SPaul Zimmerman 
3327acd85e0SPaul Zimmerman 	evt->lpos = 0;
3337acd85e0SPaul Zimmerman 
334660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), 0);
335660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), 0);
336660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK
33768d6a01bSFelipe Balbi 			| DWC3_GEVNTSIZ_SIZE(0));
338660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
33972246da4SFelipe Balbi }
34072246da4SFelipe Balbi 
3410ffcaf37SFelipe Balbi static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
3420ffcaf37SFelipe Balbi {
3430ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
3440ffcaf37SFelipe Balbi 		return 0;
3450ffcaf37SFelipe Balbi 
3460ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
3470ffcaf37SFelipe Balbi 		return 0;
3480ffcaf37SFelipe Balbi 
3490ffcaf37SFelipe Balbi 	dwc->scratchbuf = kmalloc_array(dwc->nr_scratch,
3500ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, GFP_KERNEL);
3510ffcaf37SFelipe Balbi 	if (!dwc->scratchbuf)
3520ffcaf37SFelipe Balbi 		return -ENOMEM;
3530ffcaf37SFelipe Balbi 
3540ffcaf37SFelipe Balbi 	return 0;
3550ffcaf37SFelipe Balbi }
3560ffcaf37SFelipe Balbi 
3570ffcaf37SFelipe Balbi static int dwc3_setup_scratch_buffers(struct dwc3 *dwc)
3580ffcaf37SFelipe Balbi {
3590ffcaf37SFelipe Balbi 	dma_addr_t scratch_addr;
3600ffcaf37SFelipe Balbi 	u32 param;
3610ffcaf37SFelipe Balbi 	int ret;
3620ffcaf37SFelipe Balbi 
3630ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
3640ffcaf37SFelipe Balbi 		return 0;
3650ffcaf37SFelipe Balbi 
3660ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
3670ffcaf37SFelipe Balbi 		return 0;
3680ffcaf37SFelipe Balbi 
3690ffcaf37SFelipe Balbi 	 /* should never fall here */
3700ffcaf37SFelipe Balbi 	if (!WARN_ON(dwc->scratchbuf))
3710ffcaf37SFelipe Balbi 		return 0;
3720ffcaf37SFelipe Balbi 
3730ffcaf37SFelipe Balbi 	scratch_addr = dma_map_single(dwc->dev, dwc->scratchbuf,
3740ffcaf37SFelipe Balbi 			dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
3750ffcaf37SFelipe Balbi 			DMA_BIDIRECTIONAL);
3760ffcaf37SFelipe Balbi 	if (dma_mapping_error(dwc->dev, scratch_addr)) {
3770ffcaf37SFelipe Balbi 		dev_err(dwc->dev, "failed to map scratch buffer\n");
3780ffcaf37SFelipe Balbi 		ret = -EFAULT;
3790ffcaf37SFelipe Balbi 		goto err0;
3800ffcaf37SFelipe Balbi 	}
3810ffcaf37SFelipe Balbi 
3820ffcaf37SFelipe Balbi 	dwc->scratch_addr = scratch_addr;
3830ffcaf37SFelipe Balbi 
3840ffcaf37SFelipe Balbi 	param = lower_32_bits(scratch_addr);
3850ffcaf37SFelipe Balbi 
3860ffcaf37SFelipe Balbi 	ret = dwc3_send_gadget_generic_command(dwc,
3870ffcaf37SFelipe Balbi 			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param);
3880ffcaf37SFelipe Balbi 	if (ret < 0)
3890ffcaf37SFelipe Balbi 		goto err1;
3900ffcaf37SFelipe Balbi 
3910ffcaf37SFelipe Balbi 	param = upper_32_bits(scratch_addr);
3920ffcaf37SFelipe Balbi 
3930ffcaf37SFelipe Balbi 	ret = dwc3_send_gadget_generic_command(dwc,
3940ffcaf37SFelipe Balbi 			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param);
3950ffcaf37SFelipe Balbi 	if (ret < 0)
3960ffcaf37SFelipe Balbi 		goto err1;
3970ffcaf37SFelipe Balbi 
3980ffcaf37SFelipe Balbi 	return 0;
3990ffcaf37SFelipe Balbi 
4000ffcaf37SFelipe Balbi err1:
4010ffcaf37SFelipe Balbi 	dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch *
4020ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
4030ffcaf37SFelipe Balbi 
4040ffcaf37SFelipe Balbi err0:
4050ffcaf37SFelipe Balbi 	return ret;
4060ffcaf37SFelipe Balbi }
4070ffcaf37SFelipe Balbi 
4080ffcaf37SFelipe Balbi static void dwc3_free_scratch_buffers(struct dwc3 *dwc)
4090ffcaf37SFelipe Balbi {
4100ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
4110ffcaf37SFelipe Balbi 		return;
4120ffcaf37SFelipe Balbi 
4130ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
4140ffcaf37SFelipe Balbi 		return;
4150ffcaf37SFelipe Balbi 
4160ffcaf37SFelipe Balbi 	 /* should never fall here */
4170ffcaf37SFelipe Balbi 	if (!WARN_ON(dwc->scratchbuf))
4180ffcaf37SFelipe Balbi 		return;
4190ffcaf37SFelipe Balbi 
4200ffcaf37SFelipe Balbi 	dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch *
4210ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
4220ffcaf37SFelipe Balbi 	kfree(dwc->scratchbuf);
4230ffcaf37SFelipe Balbi }
4240ffcaf37SFelipe Balbi 
425789451f6SFelipe Balbi static void dwc3_core_num_eps(struct dwc3 *dwc)
426789451f6SFelipe Balbi {
427789451f6SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
428789451f6SFelipe Balbi 
429789451f6SFelipe Balbi 	dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
430789451f6SFelipe Balbi 	dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
431789451f6SFelipe Balbi 
43273815280SFelipe Balbi 	dwc3_trace(trace_dwc3_core, "found %d IN and %d OUT endpoints",
433789451f6SFelipe Balbi 			dwc->num_in_eps, dwc->num_out_eps);
434789451f6SFelipe Balbi }
435789451f6SFelipe Balbi 
43641ac7b3aSBill Pemberton static void dwc3_cache_hwparams(struct dwc3 *dwc)
43726ceca97SFelipe Balbi {
43826ceca97SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
43926ceca97SFelipe Balbi 
44026ceca97SFelipe Balbi 	parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
44126ceca97SFelipe Balbi 	parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
44226ceca97SFelipe Balbi 	parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
44326ceca97SFelipe Balbi 	parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
44426ceca97SFelipe Balbi 	parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
44526ceca97SFelipe Balbi 	parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
44626ceca97SFelipe Balbi 	parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
44726ceca97SFelipe Balbi 	parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
44826ceca97SFelipe Balbi 	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
44926ceca97SFelipe Balbi }
45026ceca97SFelipe Balbi 
45172246da4SFelipe Balbi /**
452b5a65c40SHuang Rui  * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
453b5a65c40SHuang Rui  * @dwc: Pointer to our controller context structure
45488bc9d19SHeikki Krogerus  *
45588bc9d19SHeikki Krogerus  * Returns 0 on success. The USB PHY interfaces are configured but not
45688bc9d19SHeikki Krogerus  * initialized. The PHY interfaces and the PHYs get initialized together with
45788bc9d19SHeikki Krogerus  * the core in dwc3_core_init.
458b5a65c40SHuang Rui  */
45988bc9d19SHeikki Krogerus static int dwc3_phy_setup(struct dwc3 *dwc)
460b5a65c40SHuang Rui {
461b5a65c40SHuang Rui 	u32 reg;
46288bc9d19SHeikki Krogerus 	int ret;
463b5a65c40SHuang Rui 
464b5a65c40SHuang Rui 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
465b5a65c40SHuang Rui 
4662164a476SHuang Rui 	/*
4672164a476SHuang Rui 	 * Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
4682164a476SHuang Rui 	 * to '0' during coreConsultant configuration. So default value
4692164a476SHuang Rui 	 * will be '0' when the core is reset. Application needs to set it
4702164a476SHuang Rui 	 * to '1' after the core initialization is completed.
4712164a476SHuang Rui 	 */
4722164a476SHuang Rui 	if (dwc->revision > DWC3_REVISION_194A)
4732164a476SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_SUSPHY;
4742164a476SHuang Rui 
475b5a65c40SHuang Rui 	if (dwc->u2ss_inp3_quirk)
476b5a65c40SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
477b5a65c40SHuang Rui 
478e58dd357SRajesh Bhagat 	if (dwc->dis_rxdet_inp3_quirk)
479e58dd357SRajesh Bhagat 		reg |= DWC3_GUSB3PIPECTL_DISRXDETINP3;
480e58dd357SRajesh Bhagat 
481df31f5b3SHuang Rui 	if (dwc->req_p1p2p3_quirk)
482df31f5b3SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_REQP1P2P3;
483df31f5b3SHuang Rui 
484a2a1d0f5SHuang Rui 	if (dwc->del_p1p2p3_quirk)
485a2a1d0f5SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN;
486a2a1d0f5SHuang Rui 
48741c06ffdSHuang Rui 	if (dwc->del_phy_power_chg_quirk)
48841c06ffdSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE;
48941c06ffdSHuang Rui 
490fb67afcaSHuang Rui 	if (dwc->lfps_filter_quirk)
491fb67afcaSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_LFPSFILT;
492fb67afcaSHuang Rui 
49314f4ac53SHuang Rui 	if (dwc->rx_detect_poll_quirk)
49414f4ac53SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL;
49514f4ac53SHuang Rui 
4966b6a0c9aSHuang Rui 	if (dwc->tx_de_emphasis_quirk)
4976b6a0c9aSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis);
4986b6a0c9aSHuang Rui 
499cd72f890SFelipe Balbi 	if (dwc->dis_u3_susphy_quirk)
50059acfa20SHuang Rui 		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
50159acfa20SHuang Rui 
50200fe081dSWilliam Wu 	if (dwc->dis_del_phy_power_chg_quirk)
50300fe081dSWilliam Wu 		reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE;
50400fe081dSWilliam Wu 
505b5a65c40SHuang Rui 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
506b5a65c40SHuang Rui 
5072164a476SHuang Rui 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
5082164a476SHuang Rui 
5093e10a2ceSHeikki Krogerus 	/* Select the HS PHY interface */
5103e10a2ceSHeikki Krogerus 	switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) {
5113e10a2ceSHeikki Krogerus 	case DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI:
51243cacb03SFelipe Balbi 		if (dwc->hsphy_interface &&
51343cacb03SFelipe Balbi 				!strncmp(dwc->hsphy_interface, "utmi", 4)) {
5143e10a2ceSHeikki Krogerus 			reg &= ~DWC3_GUSB2PHYCFG_ULPI_UTMI;
51588bc9d19SHeikki Krogerus 			break;
51643cacb03SFelipe Balbi 		} else if (dwc->hsphy_interface &&
51743cacb03SFelipe Balbi 				!strncmp(dwc->hsphy_interface, "ulpi", 4)) {
5183e10a2ceSHeikki Krogerus 			reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI;
51988bc9d19SHeikki Krogerus 			dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
5203e10a2ceSHeikki Krogerus 		} else {
52188bc9d19SHeikki Krogerus 			/* Relying on default value. */
52288bc9d19SHeikki Krogerus 			if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI))
5233e10a2ceSHeikki Krogerus 				break;
5243e10a2ceSHeikki Krogerus 		}
5253e10a2ceSHeikki Krogerus 		/* FALLTHROUGH */
52688bc9d19SHeikki Krogerus 	case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI:
52788bc9d19SHeikki Krogerus 		/* Making sure the interface and PHY are operational */
52888bc9d19SHeikki Krogerus 		ret = dwc3_soft_reset(dwc);
52988bc9d19SHeikki Krogerus 		if (ret)
53088bc9d19SHeikki Krogerus 			return ret;
53188bc9d19SHeikki Krogerus 
53288bc9d19SHeikki Krogerus 		udelay(1);
53388bc9d19SHeikki Krogerus 
53488bc9d19SHeikki Krogerus 		ret = dwc3_ulpi_init(dwc);
53588bc9d19SHeikki Krogerus 		if (ret)
53688bc9d19SHeikki Krogerus 			return ret;
53788bc9d19SHeikki Krogerus 		/* FALLTHROUGH */
5383e10a2ceSHeikki Krogerus 	default:
5393e10a2ceSHeikki Krogerus 		break;
5403e10a2ceSHeikki Krogerus 	}
5413e10a2ceSHeikki Krogerus 
54232f2ed86SWilliam Wu 	switch (dwc->hsphy_mode) {
54332f2ed86SWilliam Wu 	case USBPHY_INTERFACE_MODE_UTMI:
54432f2ed86SWilliam Wu 		reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
54532f2ed86SWilliam Wu 		       DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
54632f2ed86SWilliam Wu 		reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_8_BIT) |
54732f2ed86SWilliam Wu 		       DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_8_BIT);
54832f2ed86SWilliam Wu 		break;
54932f2ed86SWilliam Wu 	case USBPHY_INTERFACE_MODE_UTMIW:
55032f2ed86SWilliam Wu 		reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
55132f2ed86SWilliam Wu 		       DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
55232f2ed86SWilliam Wu 		reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_16_BIT) |
55332f2ed86SWilliam Wu 		       DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT);
55432f2ed86SWilliam Wu 		break;
55532f2ed86SWilliam Wu 	default:
55632f2ed86SWilliam Wu 		break;
55732f2ed86SWilliam Wu 	}
55832f2ed86SWilliam Wu 
5592164a476SHuang Rui 	/*
5602164a476SHuang Rui 	 * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
5612164a476SHuang Rui 	 * '0' during coreConsultant configuration. So default value will
5622164a476SHuang Rui 	 * be '0' when the core is reset. Application needs to set it to
5632164a476SHuang Rui 	 * '1' after the core initialization is completed.
5642164a476SHuang Rui 	 */
5652164a476SHuang Rui 	if (dwc->revision > DWC3_REVISION_194A)
5662164a476SHuang Rui 		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
5672164a476SHuang Rui 
568cd72f890SFelipe Balbi 	if (dwc->dis_u2_susphy_quirk)
5690effe0a3SHuang Rui 		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
5700effe0a3SHuang Rui 
571ec791d14SJohn Youn 	if (dwc->dis_enblslpm_quirk)
572ec791d14SJohn Youn 		reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
573ec791d14SJohn Youn 
57416199f33SWilliam Wu 	if (dwc->dis_u2_freeclk_exists_quirk)
57516199f33SWilliam Wu 		reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
57616199f33SWilliam Wu 
5772164a476SHuang Rui 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
57888bc9d19SHeikki Krogerus 
57988bc9d19SHeikki Krogerus 	return 0;
580b5a65c40SHuang Rui }
581b5a65c40SHuang Rui 
582c499ff71SFelipe Balbi static void dwc3_core_exit(struct dwc3 *dwc)
583c499ff71SFelipe Balbi {
584c499ff71SFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
585c499ff71SFelipe Balbi 
586c499ff71SFelipe Balbi 	usb_phy_shutdown(dwc->usb2_phy);
587c499ff71SFelipe Balbi 	usb_phy_shutdown(dwc->usb3_phy);
588c499ff71SFelipe Balbi 	phy_exit(dwc->usb2_generic_phy);
589c499ff71SFelipe Balbi 	phy_exit(dwc->usb3_generic_phy);
590c499ff71SFelipe Balbi 
591c499ff71SFelipe Balbi 	usb_phy_set_suspend(dwc->usb2_phy, 1);
592c499ff71SFelipe Balbi 	usb_phy_set_suspend(dwc->usb3_phy, 1);
593c499ff71SFelipe Balbi 	phy_power_off(dwc->usb2_generic_phy);
594c499ff71SFelipe Balbi 	phy_power_off(dwc->usb3_generic_phy);
595c499ff71SFelipe Balbi }
596c499ff71SFelipe Balbi 
597b5a65c40SHuang Rui /**
59872246da4SFelipe Balbi  * dwc3_core_init - Low-level initialization of DWC3 Core
59972246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
60072246da4SFelipe Balbi  *
60172246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
60272246da4SFelipe Balbi  */
60341ac7b3aSBill Pemberton static int dwc3_core_init(struct dwc3 *dwc)
60472246da4SFelipe Balbi {
6050ffcaf37SFelipe Balbi 	u32			hwparams4 = dwc->hwparams.hwparams4;
60672246da4SFelipe Balbi 	u32			reg;
60772246da4SFelipe Balbi 	int			ret;
60872246da4SFelipe Balbi 
6097650bd74SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
6107650bd74SSebastian Andrzej Siewior 	/* This should read as U3 followed by revision number */
611690fb371SJohn Youn 	if ((reg & DWC3_GSNPSID_MASK) == 0x55330000) {
612690fb371SJohn Youn 		/* Detected DWC_usb3 IP */
613690fb371SJohn Youn 		dwc->revision = reg;
614690fb371SJohn Youn 	} else if ((reg & DWC3_GSNPSID_MASK) == 0x33310000) {
615690fb371SJohn Youn 		/* Detected DWC_usb31 IP */
616690fb371SJohn Youn 		dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER);
617690fb371SJohn Youn 		dwc->revision |= DWC3_REVISION_IS_DWC31;
618690fb371SJohn Youn 	} else {
6197650bd74SSebastian Andrzej Siewior 		dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
6207650bd74SSebastian Andrzej Siewior 		ret = -ENODEV;
6217650bd74SSebastian Andrzej Siewior 		goto err0;
6227650bd74SSebastian Andrzej Siewior 	}
6237650bd74SSebastian Andrzej Siewior 
624fa0ea13eSFelipe Balbi 	/*
625fa0ea13eSFelipe Balbi 	 * Write Linux Version Code to our GUID register so it's easy to figure
626fa0ea13eSFelipe Balbi 	 * out which kernel version a bug was found.
627fa0ea13eSFelipe Balbi 	 */
628fa0ea13eSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE);
629fa0ea13eSFelipe Balbi 
6300e1e5c47SPaul Zimmerman 	/* Handle USB2.0-only core configuration */
6310e1e5c47SPaul Zimmerman 	if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
6320e1e5c47SPaul Zimmerman 			DWC3_GHWPARAMS3_SSPHY_IFC_DIS) {
6330e1e5c47SPaul Zimmerman 		if (dwc->maximum_speed == USB_SPEED_SUPER)
6340e1e5c47SPaul Zimmerman 			dwc->maximum_speed = USB_SPEED_HIGH;
6350e1e5c47SPaul Zimmerman 	}
6360e1e5c47SPaul Zimmerman 
63772246da4SFelipe Balbi 	/* issue device SoftReset too */
638c5cc74e8SHeikki Krogerus 	ret = dwc3_soft_reset(dwc);
639c5cc74e8SHeikki Krogerus 	if (ret)
64072246da4SFelipe Balbi 		goto err0;
64172246da4SFelipe Balbi 
64257303488SKishon Vijay Abraham I 	ret = dwc3_core_soft_reset(dwc);
64357303488SKishon Vijay Abraham I 	if (ret)
64457303488SKishon Vijay Abraham I 		goto err0;
64558a0f23fSPratyush Anand 
646c499ff71SFelipe Balbi 	ret = dwc3_phy_setup(dwc);
647c499ff71SFelipe Balbi 	if (ret)
648c499ff71SFelipe Balbi 		goto err0;
649c499ff71SFelipe Balbi 
6504878a028SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
6513e87c42aSPaul Zimmerman 	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
6524878a028SSebastian Andrzej Siewior 
653164d7731SSebastian Andrzej Siewior 	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
6544878a028SSebastian Andrzej Siewior 	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
65532a4a135SFelipe Balbi 		/**
65632a4a135SFelipe Balbi 		 * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an
65732a4a135SFelipe Balbi 		 * issue which would cause xHCI compliance tests to fail.
65832a4a135SFelipe Balbi 		 *
65932a4a135SFelipe Balbi 		 * Because of that we cannot enable clock gating on such
66032a4a135SFelipe Balbi 		 * configurations.
66132a4a135SFelipe Balbi 		 *
66232a4a135SFelipe Balbi 		 * Refers to:
66332a4a135SFelipe Balbi 		 *
66432a4a135SFelipe Balbi 		 * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based
66532a4a135SFelipe Balbi 		 * SOF/ITP Mode Used
66632a4a135SFelipe Balbi 		 */
66732a4a135SFelipe Balbi 		if ((dwc->dr_mode == USB_DR_MODE_HOST ||
66832a4a135SFelipe Balbi 				dwc->dr_mode == USB_DR_MODE_OTG) &&
66932a4a135SFelipe Balbi 				(dwc->revision >= DWC3_REVISION_210A &&
67032a4a135SFelipe Balbi 				dwc->revision <= DWC3_REVISION_250A))
67132a4a135SFelipe Balbi 			reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC;
67232a4a135SFelipe Balbi 		else
6734878a028SSebastian Andrzej Siewior 			reg &= ~DWC3_GCTL_DSBLCLKGTNG;
6744878a028SSebastian Andrzej Siewior 		break;
6750ffcaf37SFelipe Balbi 	case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
6760ffcaf37SFelipe Balbi 		/* enable hibernation here */
6770ffcaf37SFelipe Balbi 		dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);
6782eac3992SHuang Rui 
6792eac3992SHuang Rui 		/*
6802eac3992SHuang Rui 		 * REVISIT Enabling this bit so that host-mode hibernation
6812eac3992SHuang Rui 		 * will work. Device-mode hibernation is not yet implemented.
6822eac3992SHuang Rui 		 */
6832eac3992SHuang Rui 		reg |= DWC3_GCTL_GBLHIBERNATIONEN;
6840ffcaf37SFelipe Balbi 		break;
6854878a028SSebastian Andrzej Siewior 	default:
6861407bf13SFelipe Balbi 		dwc3_trace(trace_dwc3_core, "No power optimization available\n");
6874878a028SSebastian Andrzej Siewior 	}
6884878a028SSebastian Andrzej Siewior 
689946bd579SHuang Rui 	/* check if current dwc3 is on simulation board */
690946bd579SHuang Rui 	if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) {
6911407bf13SFelipe Balbi 		dwc3_trace(trace_dwc3_core,
6921407bf13SFelipe Balbi 				"running on FPGA platform\n");
693946bd579SHuang Rui 		dwc->is_fpga = true;
694946bd579SHuang Rui 	}
695946bd579SHuang Rui 
6963b81221aSHuang Rui 	WARN_ONCE(dwc->disable_scramble_quirk && !dwc->is_fpga,
6973b81221aSHuang Rui 			"disable_scramble cannot be used on non-FPGA builds\n");
6983b81221aSHuang Rui 
6993b81221aSHuang Rui 	if (dwc->disable_scramble_quirk && dwc->is_fpga)
7003b81221aSHuang Rui 		reg |= DWC3_GCTL_DISSCRAMBLE;
7013b81221aSHuang Rui 	else
7023b81221aSHuang Rui 		reg &= ~DWC3_GCTL_DISSCRAMBLE;
7033b81221aSHuang Rui 
7049a5b2f31SHuang Rui 	if (dwc->u2exit_lfps_quirk)
7059a5b2f31SHuang Rui 		reg |= DWC3_GCTL_U2EXIT_LFPS;
7069a5b2f31SHuang Rui 
7074878a028SSebastian Andrzej Siewior 	/*
7084878a028SSebastian Andrzej Siewior 	 * WORKAROUND: DWC3 revisions <1.90a have a bug
7091d046793SPaul Zimmerman 	 * where the device can fail to connect at SuperSpeed
7104878a028SSebastian Andrzej Siewior 	 * and falls back to high-speed mode which causes
7111d046793SPaul Zimmerman 	 * the device to enter a Connect/Disconnect loop
7124878a028SSebastian Andrzej Siewior 	 */
7134878a028SSebastian Andrzej Siewior 	if (dwc->revision < DWC3_REVISION_190A)
7144878a028SSebastian Andrzej Siewior 		reg |= DWC3_GCTL_U2RSTECN;
7154878a028SSebastian Andrzej Siewior 
7164878a028SSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
7174878a028SSebastian Andrzej Siewior 
718c499ff71SFelipe Balbi 	dwc3_core_num_eps(dwc);
7190ffcaf37SFelipe Balbi 
7200ffcaf37SFelipe Balbi 	ret = dwc3_setup_scratch_buffers(dwc);
7210ffcaf37SFelipe Balbi 	if (ret)
722c499ff71SFelipe Balbi 		goto err1;
723c499ff71SFelipe Balbi 
724c499ff71SFelipe Balbi 	/* Adjust Frame Length */
725c499ff71SFelipe Balbi 	dwc3_frame_length_adjustment(dwc);
726c499ff71SFelipe Balbi 
727c499ff71SFelipe Balbi 	usb_phy_set_suspend(dwc->usb2_phy, 0);
728c499ff71SFelipe Balbi 	usb_phy_set_suspend(dwc->usb3_phy, 0);
729c499ff71SFelipe Balbi 	ret = phy_power_on(dwc->usb2_generic_phy);
730c499ff71SFelipe Balbi 	if (ret < 0)
7310ffcaf37SFelipe Balbi 		goto err2;
7320ffcaf37SFelipe Balbi 
733c499ff71SFelipe Balbi 	ret = phy_power_on(dwc->usb3_generic_phy);
734c499ff71SFelipe Balbi 	if (ret < 0)
735c499ff71SFelipe Balbi 		goto err3;
736c499ff71SFelipe Balbi 
737c499ff71SFelipe Balbi 	ret = dwc3_event_buffers_setup(dwc);
738c499ff71SFelipe Balbi 	if (ret) {
739c499ff71SFelipe Balbi 		dev_err(dwc->dev, "failed to setup event buffers\n");
740c499ff71SFelipe Balbi 		goto err4;
741c499ff71SFelipe Balbi 	}
742c499ff71SFelipe Balbi 
74300af6233SBaolin Wang 	switch (dwc->dr_mode) {
74400af6233SBaolin Wang 	case USB_DR_MODE_PERIPHERAL:
74500af6233SBaolin Wang 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
74600af6233SBaolin Wang 		break;
74700af6233SBaolin Wang 	case USB_DR_MODE_HOST:
74800af6233SBaolin Wang 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
74900af6233SBaolin Wang 		break;
75000af6233SBaolin Wang 	case USB_DR_MODE_OTG:
75100af6233SBaolin Wang 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
75200af6233SBaolin Wang 		break;
75300af6233SBaolin Wang 	default:
75400af6233SBaolin Wang 		dev_warn(dwc->dev, "Unsupported mode %d\n", dwc->dr_mode);
75500af6233SBaolin Wang 		break;
75600af6233SBaolin Wang 	}
75700af6233SBaolin Wang 
75806281d46SJohn Youn 	/*
75906281d46SJohn Youn 	 * ENDXFER polling is available on version 3.10a and later of
76006281d46SJohn Youn 	 * the DWC_usb3 controller. It is NOT available in the
76106281d46SJohn Youn 	 * DWC_usb31 controller.
76206281d46SJohn Youn 	 */
76306281d46SJohn Youn 	if (!dwc3_is_usb31(dwc) && dwc->revision >= DWC3_REVISION_310A) {
76406281d46SJohn Youn 		reg = dwc3_readl(dwc->regs, DWC3_GUCTL2);
76506281d46SJohn Youn 		reg |= DWC3_GUCTL2_RST_ACTBITLATER;
76606281d46SJohn Youn 		dwc3_writel(dwc->regs, DWC3_GUCTL2, reg);
76706281d46SJohn Youn 	}
76806281d46SJohn Youn 
76972246da4SFelipe Balbi 	return 0;
77072246da4SFelipe Balbi 
771c499ff71SFelipe Balbi err4:
772c499ff71SFelipe Balbi 	phy_power_off(dwc->usb2_generic_phy);
773c499ff71SFelipe Balbi 
774c499ff71SFelipe Balbi err3:
775c499ff71SFelipe Balbi 	phy_power_off(dwc->usb3_generic_phy);
776c499ff71SFelipe Balbi 
7770ffcaf37SFelipe Balbi err2:
778c499ff71SFelipe Balbi 	usb_phy_set_suspend(dwc->usb2_phy, 1);
779c499ff71SFelipe Balbi 	usb_phy_set_suspend(dwc->usb3_phy, 1);
780c499ff71SFelipe Balbi 	dwc3_core_exit(dwc);
7810ffcaf37SFelipe Balbi 
7820ffcaf37SFelipe Balbi err1:
7830ffcaf37SFelipe Balbi 	usb_phy_shutdown(dwc->usb2_phy);
7840ffcaf37SFelipe Balbi 	usb_phy_shutdown(dwc->usb3_phy);
78557303488SKishon Vijay Abraham I 	phy_exit(dwc->usb2_generic_phy);
78657303488SKishon Vijay Abraham I 	phy_exit(dwc->usb3_generic_phy);
7870ffcaf37SFelipe Balbi 
78872246da4SFelipe Balbi err0:
78972246da4SFelipe Balbi 	return ret;
79072246da4SFelipe Balbi }
79172246da4SFelipe Balbi 
7923c9f94acSFelipe Balbi static int dwc3_core_get_phy(struct dwc3 *dwc)
79372246da4SFelipe Balbi {
7943c9f94acSFelipe Balbi 	struct device		*dev = dwc->dev;
795941ea361SFelipe Balbi 	struct device_node	*node = dev->of_node;
7963c9f94acSFelipe Balbi 	int ret;
79772246da4SFelipe Balbi 
7985088b6f5SKishon Vijay Abraham I 	if (node) {
7995088b6f5SKishon Vijay Abraham I 		dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
8005088b6f5SKishon Vijay Abraham I 		dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
801bb674907SFelipe Balbi 	} else {
802bb674907SFelipe Balbi 		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
803bb674907SFelipe Balbi 		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
8045088b6f5SKishon Vijay Abraham I 	}
8055088b6f5SKishon Vijay Abraham I 
806d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb2_phy)) {
807d105e7f8SFelipe Balbi 		ret = PTR_ERR(dwc->usb2_phy);
808122f06e6SKishon Vijay Abraham I 		if (ret == -ENXIO || ret == -ENODEV) {
809122f06e6SKishon Vijay Abraham I 			dwc->usb2_phy = NULL;
810122f06e6SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
811d105e7f8SFelipe Balbi 			return ret;
812122f06e6SKishon Vijay Abraham I 		} else {
81351e1e7bcSFelipe Balbi 			dev_err(dev, "no usb2 phy configured\n");
814122f06e6SKishon Vijay Abraham I 			return ret;
815122f06e6SKishon Vijay Abraham I 		}
81651e1e7bcSFelipe Balbi 	}
81751e1e7bcSFelipe Balbi 
818d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb3_phy)) {
819315955d7SRuchika Kharwar 		ret = PTR_ERR(dwc->usb3_phy);
820122f06e6SKishon Vijay Abraham I 		if (ret == -ENXIO || ret == -ENODEV) {
821122f06e6SKishon Vijay Abraham I 			dwc->usb3_phy = NULL;
822122f06e6SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
823d105e7f8SFelipe Balbi 			return ret;
824122f06e6SKishon Vijay Abraham I 		} else {
82551e1e7bcSFelipe Balbi 			dev_err(dev, "no usb3 phy configured\n");
826122f06e6SKishon Vijay Abraham I 			return ret;
827122f06e6SKishon Vijay Abraham I 		}
82851e1e7bcSFelipe Balbi 	}
82951e1e7bcSFelipe Balbi 
83057303488SKishon Vijay Abraham I 	dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy");
83157303488SKishon Vijay Abraham I 	if (IS_ERR(dwc->usb2_generic_phy)) {
83257303488SKishon Vijay Abraham I 		ret = PTR_ERR(dwc->usb2_generic_phy);
83357303488SKishon Vijay Abraham I 		if (ret == -ENOSYS || ret == -ENODEV) {
83457303488SKishon Vijay Abraham I 			dwc->usb2_generic_phy = NULL;
83557303488SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
83657303488SKishon Vijay Abraham I 			return ret;
83757303488SKishon Vijay Abraham I 		} else {
83857303488SKishon Vijay Abraham I 			dev_err(dev, "no usb2 phy configured\n");
83957303488SKishon Vijay Abraham I 			return ret;
84057303488SKishon Vijay Abraham I 		}
84157303488SKishon Vijay Abraham I 	}
84257303488SKishon Vijay Abraham I 
84357303488SKishon Vijay Abraham I 	dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy");
84457303488SKishon Vijay Abraham I 	if (IS_ERR(dwc->usb3_generic_phy)) {
84557303488SKishon Vijay Abraham I 		ret = PTR_ERR(dwc->usb3_generic_phy);
84657303488SKishon Vijay Abraham I 		if (ret == -ENOSYS || ret == -ENODEV) {
84757303488SKishon Vijay Abraham I 			dwc->usb3_generic_phy = NULL;
84857303488SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
84957303488SKishon Vijay Abraham I 			return ret;
85057303488SKishon Vijay Abraham I 		} else {
85157303488SKishon Vijay Abraham I 			dev_err(dev, "no usb3 phy configured\n");
85257303488SKishon Vijay Abraham I 			return ret;
85357303488SKishon Vijay Abraham I 		}
85457303488SKishon Vijay Abraham I 	}
85557303488SKishon Vijay Abraham I 
8563c9f94acSFelipe Balbi 	return 0;
8573c9f94acSFelipe Balbi }
8583c9f94acSFelipe Balbi 
8595f94adfeSFelipe Balbi static int dwc3_core_init_mode(struct dwc3 *dwc)
8605f94adfeSFelipe Balbi {
8615f94adfeSFelipe Balbi 	struct device *dev = dwc->dev;
8625f94adfeSFelipe Balbi 	int ret;
8635f94adfeSFelipe Balbi 
8645f94adfeSFelipe Balbi 	switch (dwc->dr_mode) {
8655f94adfeSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
8665f94adfeSFelipe Balbi 		ret = dwc3_gadget_init(dwc);
8675f94adfeSFelipe Balbi 		if (ret) {
8689522def4SRoger Quadros 			if (ret != -EPROBE_DEFER)
8695f94adfeSFelipe Balbi 				dev_err(dev, "failed to initialize gadget\n");
8705f94adfeSFelipe Balbi 			return ret;
8715f94adfeSFelipe Balbi 		}
8725f94adfeSFelipe Balbi 		break;
8735f94adfeSFelipe Balbi 	case USB_DR_MODE_HOST:
8745f94adfeSFelipe Balbi 		ret = dwc3_host_init(dwc);
8755f94adfeSFelipe Balbi 		if (ret) {
8769522def4SRoger Quadros 			if (ret != -EPROBE_DEFER)
8775f94adfeSFelipe Balbi 				dev_err(dev, "failed to initialize host\n");
8785f94adfeSFelipe Balbi 			return ret;
8795f94adfeSFelipe Balbi 		}
8805f94adfeSFelipe Balbi 		break;
8815f94adfeSFelipe Balbi 	case USB_DR_MODE_OTG:
8825f94adfeSFelipe Balbi 		ret = dwc3_host_init(dwc);
8835f94adfeSFelipe Balbi 		if (ret) {
8849522def4SRoger Quadros 			if (ret != -EPROBE_DEFER)
8855f94adfeSFelipe Balbi 				dev_err(dev, "failed to initialize host\n");
8865f94adfeSFelipe Balbi 			return ret;
8875f94adfeSFelipe Balbi 		}
8885f94adfeSFelipe Balbi 
8895f94adfeSFelipe Balbi 		ret = dwc3_gadget_init(dwc);
8905f94adfeSFelipe Balbi 		if (ret) {
8919522def4SRoger Quadros 			if (ret != -EPROBE_DEFER)
8925f94adfeSFelipe Balbi 				dev_err(dev, "failed to initialize gadget\n");
8935f94adfeSFelipe Balbi 			return ret;
8945f94adfeSFelipe Balbi 		}
8955f94adfeSFelipe Balbi 		break;
8965f94adfeSFelipe Balbi 	default:
8975f94adfeSFelipe Balbi 		dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
8985f94adfeSFelipe Balbi 		return -EINVAL;
8995f94adfeSFelipe Balbi 	}
9005f94adfeSFelipe Balbi 
9015f94adfeSFelipe Balbi 	return 0;
9025f94adfeSFelipe Balbi }
9035f94adfeSFelipe Balbi 
9045f94adfeSFelipe Balbi static void dwc3_core_exit_mode(struct dwc3 *dwc)
9055f94adfeSFelipe Balbi {
9065f94adfeSFelipe Balbi 	switch (dwc->dr_mode) {
9075f94adfeSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
9085f94adfeSFelipe Balbi 		dwc3_gadget_exit(dwc);
9095f94adfeSFelipe Balbi 		break;
9105f94adfeSFelipe Balbi 	case USB_DR_MODE_HOST:
9115f94adfeSFelipe Balbi 		dwc3_host_exit(dwc);
9125f94adfeSFelipe Balbi 		break;
9135f94adfeSFelipe Balbi 	case USB_DR_MODE_OTG:
9145f94adfeSFelipe Balbi 		dwc3_host_exit(dwc);
9155f94adfeSFelipe Balbi 		dwc3_gadget_exit(dwc);
9165f94adfeSFelipe Balbi 		break;
9175f94adfeSFelipe Balbi 	default:
9185f94adfeSFelipe Balbi 		/* do nothing */
9195f94adfeSFelipe Balbi 		break;
9205f94adfeSFelipe Balbi 	}
9215f94adfeSFelipe Balbi }
9225f94adfeSFelipe Balbi 
9233c9f94acSFelipe Balbi #define DWC3_ALIGN_MASK		(16 - 1)
9243c9f94acSFelipe Balbi 
9253c9f94acSFelipe Balbi static int dwc3_probe(struct platform_device *pdev)
9263c9f94acSFelipe Balbi {
9273c9f94acSFelipe Balbi 	struct device		*dev = &pdev->dev;
9283c9f94acSFelipe Balbi 	struct resource		*res;
9293c9f94acSFelipe Balbi 	struct dwc3		*dwc;
93080caf7d2SHuang Rui 	u8			lpm_nyet_threshold;
9316b6a0c9aSHuang Rui 	u8			tx_de_emphasis;
932460d098cSHuang Rui 	u8			hird_threshold;
9333c9f94acSFelipe Balbi 
934b09e99eeSAndy Shevchenko 	int			ret;
9353c9f94acSFelipe Balbi 
9363c9f94acSFelipe Balbi 	void __iomem		*regs;
9373c9f94acSFelipe Balbi 	void			*mem;
9383c9f94acSFelipe Balbi 
9393c9f94acSFelipe Balbi 	mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
940734d5a53SJingoo Han 	if (!mem)
9413c9f94acSFelipe Balbi 		return -ENOMEM;
942734d5a53SJingoo Han 
9433c9f94acSFelipe Balbi 	dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
9443c9f94acSFelipe Balbi 	dwc->mem = mem;
9453c9f94acSFelipe Balbi 	dwc->dev = dev;
9463c9f94acSFelipe Balbi 
9473c9f94acSFelipe Balbi 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
9483c9f94acSFelipe Balbi 	if (!res) {
9493c9f94acSFelipe Balbi 		dev_err(dev, "missing memory resource\n");
9503c9f94acSFelipe Balbi 		return -ENODEV;
9513c9f94acSFelipe Balbi 	}
9523c9f94acSFelipe Balbi 
953f32a5e23SVivek Gautam 	dwc->xhci_resources[0].start = res->start;
954f32a5e23SVivek Gautam 	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
955f32a5e23SVivek Gautam 					DWC3_XHCI_REGS_END;
956f32a5e23SVivek Gautam 	dwc->xhci_resources[0].flags = res->flags;
957f32a5e23SVivek Gautam 	dwc->xhci_resources[0].name = res->name;
958f32a5e23SVivek Gautam 
959f32a5e23SVivek Gautam 	res->start += DWC3_GLOBALS_REGS_START;
960f32a5e23SVivek Gautam 
961f32a5e23SVivek Gautam 	/*
962f32a5e23SVivek Gautam 	 * Request memory region but exclude xHCI regs,
963f32a5e23SVivek Gautam 	 * since it will be requested by the xhci-plat driver.
964f32a5e23SVivek Gautam 	 */
965f32a5e23SVivek Gautam 	regs = devm_ioremap_resource(dev, res);
9663da1f6eeSFelipe Balbi 	if (IS_ERR(regs)) {
9673da1f6eeSFelipe Balbi 		ret = PTR_ERR(regs);
9683da1f6eeSFelipe Balbi 		goto err0;
9693da1f6eeSFelipe Balbi 	}
970f32a5e23SVivek Gautam 
971f32a5e23SVivek Gautam 	dwc->regs	= regs;
972f32a5e23SVivek Gautam 	dwc->regs_size	= resource_size(res);
973f32a5e23SVivek Gautam 
97480caf7d2SHuang Rui 	/* default to highest possible threshold */
97580caf7d2SHuang Rui 	lpm_nyet_threshold = 0xff;
97680caf7d2SHuang Rui 
9776b6a0c9aSHuang Rui 	/* default to -3.5dB de-emphasis */
9786b6a0c9aSHuang Rui 	tx_de_emphasis = 1;
9796b6a0c9aSHuang Rui 
980460d098cSHuang Rui 	/*
981460d098cSHuang Rui 	 * default to assert utmi_sleep_n and use maximum allowed HIRD
982460d098cSHuang Rui 	 * threshold value of 0b1100
983460d098cSHuang Rui 	 */
984460d098cSHuang Rui 	hird_threshold = 12;
985460d098cSHuang Rui 
98663863b98SHeikki Krogerus 	dwc->maximum_speed = usb_get_maximum_speed(dev);
98706e7114fSHeikki Krogerus 	dwc->dr_mode = usb_get_dr_mode(dev);
98832f2ed86SWilliam Wu 	dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node);
98963863b98SHeikki Krogerus 
9903d128919SHeikki Krogerus 	dwc->has_lpm_erratum = device_property_read_bool(dev,
99180caf7d2SHuang Rui 				"snps,has-lpm-erratum");
9923d128919SHeikki Krogerus 	device_property_read_u8(dev, "snps,lpm-nyet-threshold",
99380caf7d2SHuang Rui 				&lpm_nyet_threshold);
9943d128919SHeikki Krogerus 	dwc->is_utmi_l1_suspend = device_property_read_bool(dev,
995460d098cSHuang Rui 				"snps,is-utmi-l1-suspend");
9963d128919SHeikki Krogerus 	device_property_read_u8(dev, "snps,hird-threshold",
997460d098cSHuang Rui 				&hird_threshold);
9983d128919SHeikki Krogerus 	dwc->usb3_lpm_capable = device_property_read_bool(dev,
999eac68e8fSRobert Baldyga 				"snps,usb3_lpm_capable");
10003c9f94acSFelipe Balbi 
10013d128919SHeikki Krogerus 	dwc->disable_scramble_quirk = device_property_read_bool(dev,
10023b81221aSHuang Rui 				"snps,disable_scramble_quirk");
10033d128919SHeikki Krogerus 	dwc->u2exit_lfps_quirk = device_property_read_bool(dev,
10049a5b2f31SHuang Rui 				"snps,u2exit_lfps_quirk");
10053d128919SHeikki Krogerus 	dwc->u2ss_inp3_quirk = device_property_read_bool(dev,
1006b5a65c40SHuang Rui 				"snps,u2ss_inp3_quirk");
10073d128919SHeikki Krogerus 	dwc->req_p1p2p3_quirk = device_property_read_bool(dev,
1008df31f5b3SHuang Rui 				"snps,req_p1p2p3_quirk");
10093d128919SHeikki Krogerus 	dwc->del_p1p2p3_quirk = device_property_read_bool(dev,
1010a2a1d0f5SHuang Rui 				"snps,del_p1p2p3_quirk");
10113d128919SHeikki Krogerus 	dwc->del_phy_power_chg_quirk = device_property_read_bool(dev,
101241c06ffdSHuang Rui 				"snps,del_phy_power_chg_quirk");
10133d128919SHeikki Krogerus 	dwc->lfps_filter_quirk = device_property_read_bool(dev,
1014fb67afcaSHuang Rui 				"snps,lfps_filter_quirk");
10153d128919SHeikki Krogerus 	dwc->rx_detect_poll_quirk = device_property_read_bool(dev,
101614f4ac53SHuang Rui 				"snps,rx_detect_poll_quirk");
10173d128919SHeikki Krogerus 	dwc->dis_u3_susphy_quirk = device_property_read_bool(dev,
101859acfa20SHuang Rui 				"snps,dis_u3_susphy_quirk");
10193d128919SHeikki Krogerus 	dwc->dis_u2_susphy_quirk = device_property_read_bool(dev,
10200effe0a3SHuang Rui 				"snps,dis_u2_susphy_quirk");
1021ec791d14SJohn Youn 	dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
1022ec791d14SJohn Youn 				"snps,dis_enblslpm_quirk");
1023e58dd357SRajesh Bhagat 	dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
1024e58dd357SRajesh Bhagat 				"snps,dis_rxdet_inp3_quirk");
102516199f33SWilliam Wu 	dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
102616199f33SWilliam Wu 				"snps,dis-u2-freeclk-exists-quirk");
102700fe081dSWilliam Wu 	dwc->dis_del_phy_power_chg_quirk = device_property_read_bool(dev,
102800fe081dSWilliam Wu 				"snps,dis-del-phy-power-chg-quirk");
10296b6a0c9aSHuang Rui 
10303d128919SHeikki Krogerus 	dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
10316b6a0c9aSHuang Rui 				"snps,tx_de_emphasis_quirk");
10323d128919SHeikki Krogerus 	device_property_read_u8(dev, "snps,tx_de_emphasis",
10336b6a0c9aSHuang Rui 				&tx_de_emphasis);
10343d128919SHeikki Krogerus 	device_property_read_string(dev, "snps,hsphy_interface",
10353e10a2ceSHeikki Krogerus 				    &dwc->hsphy_interface);
10363d128919SHeikki Krogerus 	device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
1037bcdb3272SFelipe Balbi 				 &dwc->fladj);
10383d128919SHeikki Krogerus 
103980caf7d2SHuang Rui 	dwc->lpm_nyet_threshold = lpm_nyet_threshold;
10406b6a0c9aSHuang Rui 	dwc->tx_de_emphasis = tx_de_emphasis;
104180caf7d2SHuang Rui 
1042460d098cSHuang Rui 	dwc->hird_threshold = hird_threshold
1043460d098cSHuang Rui 		| (dwc->is_utmi_l1_suspend << 4);
1044460d098cSHuang Rui 
10456c89cce0SHeikki Krogerus 	platform_set_drvdata(pdev, dwc);
10462917e718SHeikki Krogerus 	dwc3_cache_hwparams(dwc);
10476c89cce0SHeikki Krogerus 
10483c9f94acSFelipe Balbi 	ret = dwc3_core_get_phy(dwc);
10493c9f94acSFelipe Balbi 	if (ret)
10503da1f6eeSFelipe Balbi 		goto err0;
10513c9f94acSFelipe Balbi 
105272246da4SFelipe Balbi 	spin_lock_init(&dwc->lock);
105372246da4SFelipe Balbi 
105419bacdc9SHeikki Krogerus 	if (!dev->dma_mask) {
1055ddff14f1SKishon Vijay Abraham I 		dev->dma_mask = dev->parent->dma_mask;
1056ddff14f1SKishon Vijay Abraham I 		dev->dma_parms = dev->parent->dma_parms;
1057ddff14f1SKishon Vijay Abraham I 		dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
105819bacdc9SHeikki Krogerus 	}
1059ddff14f1SKishon Vijay Abraham I 
1060fc8bb91bSFelipe Balbi 	pm_runtime_set_active(dev);
1061fc8bb91bSFelipe Balbi 	pm_runtime_use_autosuspend(dev);
1062fc8bb91bSFelipe Balbi 	pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY);
1063802ca850SChanho Park 	pm_runtime_enable(dev);
106432808237SRoger Quadros 	ret = pm_runtime_get_sync(dev);
106532808237SRoger Quadros 	if (ret < 0)
106632808237SRoger Quadros 		goto err1;
106732808237SRoger Quadros 
1068802ca850SChanho Park 	pm_runtime_forbid(dev);
106972246da4SFelipe Balbi 
10703921426bSFelipe Balbi 	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
10713921426bSFelipe Balbi 	if (ret) {
10723921426bSFelipe Balbi 		dev_err(dwc->dev, "failed to allocate event buffers\n");
10733921426bSFelipe Balbi 		ret = -ENOMEM;
107432808237SRoger Quadros 		goto err2;
10753921426bSFelipe Balbi 	}
10763921426bSFelipe Balbi 
10779d6173e1SThinh Nguyen 	ret = dwc3_get_dr_mode(dwc);
10789d6173e1SThinh Nguyen 	if (ret)
10799d6173e1SThinh Nguyen 		goto err3;
108032a4a135SFelipe Balbi 
1081c499ff71SFelipe Balbi 	ret = dwc3_alloc_scratch_buffers(dwc);
1082c499ff71SFelipe Balbi 	if (ret)
108332808237SRoger Quadros 		goto err3;
1084c499ff71SFelipe Balbi 
108572246da4SFelipe Balbi 	ret = dwc3_core_init(dwc);
108672246da4SFelipe Balbi 	if (ret) {
1087802ca850SChanho Park 		dev_err(dev, "failed to initialize core\n");
108832808237SRoger Quadros 		goto err4;
108972246da4SFelipe Balbi 	}
109072246da4SFelipe Balbi 
109177966eb8SJohn Youn 	/* Check the maximum_speed parameter */
109277966eb8SJohn Youn 	switch (dwc->maximum_speed) {
109377966eb8SJohn Youn 	case USB_SPEED_LOW:
109477966eb8SJohn Youn 	case USB_SPEED_FULL:
109577966eb8SJohn Youn 	case USB_SPEED_HIGH:
109677966eb8SJohn Youn 	case USB_SPEED_SUPER:
109777966eb8SJohn Youn 	case USB_SPEED_SUPER_PLUS:
109877966eb8SJohn Youn 		break;
109977966eb8SJohn Youn 	default:
110077966eb8SJohn Youn 		dev_err(dev, "invalid maximum_speed parameter %d\n",
110177966eb8SJohn Youn 			dwc->maximum_speed);
110277966eb8SJohn Youn 		/* fall through */
110377966eb8SJohn Youn 	case USB_SPEED_UNKNOWN:
110477966eb8SJohn Youn 		/* default to superspeed */
11052c7f1bd9SJohn Youn 		dwc->maximum_speed = USB_SPEED_SUPER;
11062c7f1bd9SJohn Youn 
11072c7f1bd9SJohn Youn 		/*
11082c7f1bd9SJohn Youn 		 * default to superspeed plus if we are capable.
11092c7f1bd9SJohn Youn 		 */
11102c7f1bd9SJohn Youn 		if (dwc3_is_usb31(dwc) &&
11112c7f1bd9SJohn Youn 		    (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
11122c7f1bd9SJohn Youn 		     DWC3_GHWPARAMS3_SSPHY_IFC_GEN2))
11132c7f1bd9SJohn Youn 			dwc->maximum_speed = USB_SPEED_SUPER_PLUS;
111477966eb8SJohn Youn 
111577966eb8SJohn Youn 		break;
11162c7f1bd9SJohn Youn 	}
11172c7f1bd9SJohn Youn 
11185f94adfeSFelipe Balbi 	ret = dwc3_core_init_mode(dwc);
11195f94adfeSFelipe Balbi 	if (ret)
112032808237SRoger Quadros 		goto err5;
112172246da4SFelipe Balbi 
11224e9f3118SDu, Changbin 	dwc3_debugfs_init(dwc);
1123fc8bb91bSFelipe Balbi 	pm_runtime_put(dev);
112472246da4SFelipe Balbi 
112572246da4SFelipe Balbi 	return 0;
112672246da4SFelipe Balbi 
112732808237SRoger Quadros err5:
1128f122d33eSFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
1129f122d33eSFelipe Balbi 
113032808237SRoger Quadros err4:
1131c499ff71SFelipe Balbi 	dwc3_free_scratch_buffers(dwc);
113272246da4SFelipe Balbi 
113332808237SRoger Quadros err3:
11343921426bSFelipe Balbi 	dwc3_free_event_buffers(dwc);
113588bc9d19SHeikki Krogerus 	dwc3_ulpi_exit(dwc);
11363921426bSFelipe Balbi 
113732808237SRoger Quadros err2:
113832808237SRoger Quadros 	pm_runtime_allow(&pdev->dev);
113932808237SRoger Quadros 
114032808237SRoger Quadros err1:
114132808237SRoger Quadros 	pm_runtime_put_sync(&pdev->dev);
114232808237SRoger Quadros 	pm_runtime_disable(&pdev->dev);
114332808237SRoger Quadros 
11443da1f6eeSFelipe Balbi err0:
11453da1f6eeSFelipe Balbi 	/*
11463da1f6eeSFelipe Balbi 	 * restore res->start back to its original value so that, in case the
11473da1f6eeSFelipe Balbi 	 * probe is deferred, we don't end up getting error in request the
11483da1f6eeSFelipe Balbi 	 * memory region the next time probe is called.
11493da1f6eeSFelipe Balbi 	 */
11503da1f6eeSFelipe Balbi 	res->start -= DWC3_GLOBALS_REGS_START;
11513da1f6eeSFelipe Balbi 
115272246da4SFelipe Balbi 	return ret;
115372246da4SFelipe Balbi }
115472246da4SFelipe Balbi 
1155fb4e98abSBill Pemberton static int dwc3_remove(struct platform_device *pdev)
115672246da4SFelipe Balbi {
115772246da4SFelipe Balbi 	struct dwc3	*dwc = platform_get_drvdata(pdev);
11583da1f6eeSFelipe Balbi 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
11593da1f6eeSFelipe Balbi 
1160fc8bb91bSFelipe Balbi 	pm_runtime_get_sync(&pdev->dev);
11613da1f6eeSFelipe Balbi 	/*
11623da1f6eeSFelipe Balbi 	 * restore res->start back to its original value so that, in case the
11633da1f6eeSFelipe Balbi 	 * probe is deferred, we don't end up getting error in request the
11643da1f6eeSFelipe Balbi 	 * memory region the next time probe is called.
11653da1f6eeSFelipe Balbi 	 */
11663da1f6eeSFelipe Balbi 	res->start -= DWC3_GLOBALS_REGS_START;
116772246da4SFelipe Balbi 
1168dc99f16fSFelipe Balbi 	dwc3_debugfs_exit(dwc);
1169dc99f16fSFelipe Balbi 	dwc3_core_exit_mode(dwc);
11708ba007a9SKishon Vijay Abraham I 
117172246da4SFelipe Balbi 	dwc3_core_exit(dwc);
117288bc9d19SHeikki Krogerus 	dwc3_ulpi_exit(dwc);
117372246da4SFelipe Balbi 
1174fc8bb91bSFelipe Balbi 	pm_runtime_put_sync(&pdev->dev);
1175fc8bb91bSFelipe Balbi 	pm_runtime_allow(&pdev->dev);
1176fc8bb91bSFelipe Balbi 	pm_runtime_disable(&pdev->dev);
1177fc8bb91bSFelipe Balbi 
1178c499ff71SFelipe Balbi 	dwc3_free_event_buffers(dwc);
1179c499ff71SFelipe Balbi 	dwc3_free_scratch_buffers(dwc);
1180c499ff71SFelipe Balbi 
118172246da4SFelipe Balbi 	return 0;
118272246da4SFelipe Balbi }
118372246da4SFelipe Balbi 
1184fc8bb91bSFelipe Balbi #ifdef CONFIG_PM
1185fc8bb91bSFelipe Balbi static int dwc3_suspend_common(struct dwc3 *dwc)
11867415f17cSFelipe Balbi {
1187fc8bb91bSFelipe Balbi 	unsigned long	flags;
11887415f17cSFelipe Balbi 
1189a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
1190a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
1191a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
1192fc8bb91bSFelipe Balbi 		spin_lock_irqsave(&dwc->lock, flags);
11937415f17cSFelipe Balbi 		dwc3_gadget_suspend(dwc);
1194fc8bb91bSFelipe Balbi 		spin_unlock_irqrestore(&dwc->lock, flags);
119551f5d49aSFelipe Balbi 		break;
1196a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
11977415f17cSFelipe Balbi 	default:
119851f5d49aSFelipe Balbi 		/* do nothing */
11997415f17cSFelipe Balbi 		break;
12007415f17cSFelipe Balbi 	}
12017415f17cSFelipe Balbi 
120251f5d49aSFelipe Balbi 	dwc3_core_exit(dwc);
12035c4ad318SFelipe Balbi 
1204fc8bb91bSFelipe Balbi 	return 0;
1205fc8bb91bSFelipe Balbi }
1206fc8bb91bSFelipe Balbi 
1207fc8bb91bSFelipe Balbi static int dwc3_resume_common(struct dwc3 *dwc)
1208fc8bb91bSFelipe Balbi {
1209fc8bb91bSFelipe Balbi 	unsigned long	flags;
1210fc8bb91bSFelipe Balbi 	int		ret;
1211fc8bb91bSFelipe Balbi 
1212fc8bb91bSFelipe Balbi 	ret = dwc3_core_init(dwc);
1213fc8bb91bSFelipe Balbi 	if (ret)
1214fc8bb91bSFelipe Balbi 		return ret;
1215fc8bb91bSFelipe Balbi 
1216fc8bb91bSFelipe Balbi 	switch (dwc->dr_mode) {
1217fc8bb91bSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
1218fc8bb91bSFelipe Balbi 	case USB_DR_MODE_OTG:
1219fc8bb91bSFelipe Balbi 		spin_lock_irqsave(&dwc->lock, flags);
1220fc8bb91bSFelipe Balbi 		dwc3_gadget_resume(dwc);
1221fc8bb91bSFelipe Balbi 		spin_unlock_irqrestore(&dwc->lock, flags);
1222fc8bb91bSFelipe Balbi 		/* FALLTHROUGH */
1223fc8bb91bSFelipe Balbi 	case USB_DR_MODE_HOST:
1224fc8bb91bSFelipe Balbi 	default:
1225fc8bb91bSFelipe Balbi 		/* do nothing */
1226fc8bb91bSFelipe Balbi 		break;
1227fc8bb91bSFelipe Balbi 	}
1228fc8bb91bSFelipe Balbi 
1229fc8bb91bSFelipe Balbi 	return 0;
1230fc8bb91bSFelipe Balbi }
1231fc8bb91bSFelipe Balbi 
1232fc8bb91bSFelipe Balbi static int dwc3_runtime_checks(struct dwc3 *dwc)
1233fc8bb91bSFelipe Balbi {
1234fc8bb91bSFelipe Balbi 	switch (dwc->dr_mode) {
1235fc8bb91bSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
1236fc8bb91bSFelipe Balbi 	case USB_DR_MODE_OTG:
1237fc8bb91bSFelipe Balbi 		if (dwc->connected)
1238fc8bb91bSFelipe Balbi 			return -EBUSY;
1239fc8bb91bSFelipe Balbi 		break;
1240fc8bb91bSFelipe Balbi 	case USB_DR_MODE_HOST:
1241fc8bb91bSFelipe Balbi 	default:
1242fc8bb91bSFelipe Balbi 		/* do nothing */
1243fc8bb91bSFelipe Balbi 		break;
1244fc8bb91bSFelipe Balbi 	}
1245fc8bb91bSFelipe Balbi 
1246fc8bb91bSFelipe Balbi 	return 0;
1247fc8bb91bSFelipe Balbi }
1248fc8bb91bSFelipe Balbi 
1249fc8bb91bSFelipe Balbi static int dwc3_runtime_suspend(struct device *dev)
1250fc8bb91bSFelipe Balbi {
1251fc8bb91bSFelipe Balbi 	struct dwc3     *dwc = dev_get_drvdata(dev);
1252fc8bb91bSFelipe Balbi 	int		ret;
1253fc8bb91bSFelipe Balbi 
1254fc8bb91bSFelipe Balbi 	if (dwc3_runtime_checks(dwc))
1255fc8bb91bSFelipe Balbi 		return -EBUSY;
1256fc8bb91bSFelipe Balbi 
1257fc8bb91bSFelipe Balbi 	ret = dwc3_suspend_common(dwc);
1258fc8bb91bSFelipe Balbi 	if (ret)
1259fc8bb91bSFelipe Balbi 		return ret;
1260fc8bb91bSFelipe Balbi 
1261fc8bb91bSFelipe Balbi 	device_init_wakeup(dev, true);
1262fc8bb91bSFelipe Balbi 
1263fc8bb91bSFelipe Balbi 	return 0;
1264fc8bb91bSFelipe Balbi }
1265fc8bb91bSFelipe Balbi 
1266fc8bb91bSFelipe Balbi static int dwc3_runtime_resume(struct device *dev)
1267fc8bb91bSFelipe Balbi {
1268fc8bb91bSFelipe Balbi 	struct dwc3     *dwc = dev_get_drvdata(dev);
1269fc8bb91bSFelipe Balbi 	int		ret;
1270fc8bb91bSFelipe Balbi 
1271fc8bb91bSFelipe Balbi 	device_init_wakeup(dev, false);
1272fc8bb91bSFelipe Balbi 
1273fc8bb91bSFelipe Balbi 	ret = dwc3_resume_common(dwc);
1274fc8bb91bSFelipe Balbi 	if (ret)
1275fc8bb91bSFelipe Balbi 		return ret;
1276fc8bb91bSFelipe Balbi 
1277fc8bb91bSFelipe Balbi 	switch (dwc->dr_mode) {
1278fc8bb91bSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
1279fc8bb91bSFelipe Balbi 	case USB_DR_MODE_OTG:
1280fc8bb91bSFelipe Balbi 		dwc3_gadget_process_pending_events(dwc);
1281fc8bb91bSFelipe Balbi 		break;
1282fc8bb91bSFelipe Balbi 	case USB_DR_MODE_HOST:
1283fc8bb91bSFelipe Balbi 	default:
1284fc8bb91bSFelipe Balbi 		/* do nothing */
1285fc8bb91bSFelipe Balbi 		break;
1286fc8bb91bSFelipe Balbi 	}
1287fc8bb91bSFelipe Balbi 
1288fc8bb91bSFelipe Balbi 	pm_runtime_mark_last_busy(dev);
1289fc8bb91bSFelipe Balbi 
1290fc8bb91bSFelipe Balbi 	return 0;
1291fc8bb91bSFelipe Balbi }
1292fc8bb91bSFelipe Balbi 
1293fc8bb91bSFelipe Balbi static int dwc3_runtime_idle(struct device *dev)
1294fc8bb91bSFelipe Balbi {
1295fc8bb91bSFelipe Balbi 	struct dwc3     *dwc = dev_get_drvdata(dev);
1296fc8bb91bSFelipe Balbi 
1297fc8bb91bSFelipe Balbi 	switch (dwc->dr_mode) {
1298fc8bb91bSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
1299fc8bb91bSFelipe Balbi 	case USB_DR_MODE_OTG:
1300fc8bb91bSFelipe Balbi 		if (dwc3_runtime_checks(dwc))
1301fc8bb91bSFelipe Balbi 			return -EBUSY;
1302fc8bb91bSFelipe Balbi 		break;
1303fc8bb91bSFelipe Balbi 	case USB_DR_MODE_HOST:
1304fc8bb91bSFelipe Balbi 	default:
1305fc8bb91bSFelipe Balbi 		/* do nothing */
1306fc8bb91bSFelipe Balbi 		break;
1307fc8bb91bSFelipe Balbi 	}
1308fc8bb91bSFelipe Balbi 
1309fc8bb91bSFelipe Balbi 	pm_runtime_mark_last_busy(dev);
1310fc8bb91bSFelipe Balbi 	pm_runtime_autosuspend(dev);
1311fc8bb91bSFelipe Balbi 
1312fc8bb91bSFelipe Balbi 	return 0;
1313fc8bb91bSFelipe Balbi }
1314fc8bb91bSFelipe Balbi #endif /* CONFIG_PM */
1315fc8bb91bSFelipe Balbi 
1316fc8bb91bSFelipe Balbi #ifdef CONFIG_PM_SLEEP
1317fc8bb91bSFelipe Balbi static int dwc3_suspend(struct device *dev)
1318fc8bb91bSFelipe Balbi {
1319fc8bb91bSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
1320fc8bb91bSFelipe Balbi 	int		ret;
1321fc8bb91bSFelipe Balbi 
1322fc8bb91bSFelipe Balbi 	ret = dwc3_suspend_common(dwc);
1323fc8bb91bSFelipe Balbi 	if (ret)
1324fc8bb91bSFelipe Balbi 		return ret;
1325fc8bb91bSFelipe Balbi 
13266344475fSSekhar Nori 	pinctrl_pm_select_sleep_state(dev);
13276344475fSSekhar Nori 
13287415f17cSFelipe Balbi 	return 0;
13297415f17cSFelipe Balbi }
13307415f17cSFelipe Balbi 
13317415f17cSFelipe Balbi static int dwc3_resume(struct device *dev)
13327415f17cSFelipe Balbi {
13337415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
133457303488SKishon Vijay Abraham I 	int		ret;
13357415f17cSFelipe Balbi 
13366344475fSSekhar Nori 	pinctrl_pm_select_default_state(dev);
13376344475fSSekhar Nori 
1338fc8bb91bSFelipe Balbi 	ret = dwc3_resume_common(dwc);
133951f5d49aSFelipe Balbi 	if (ret)
13405c4ad318SFelipe Balbi 		return ret;
13415c4ad318SFelipe Balbi 
13427415f17cSFelipe Balbi 	pm_runtime_disable(dev);
13437415f17cSFelipe Balbi 	pm_runtime_set_active(dev);
13447415f17cSFelipe Balbi 	pm_runtime_enable(dev);
13457415f17cSFelipe Balbi 
13467415f17cSFelipe Balbi 	return 0;
13477415f17cSFelipe Balbi }
13487f370ed0SFelipe Balbi #endif /* CONFIG_PM_SLEEP */
13497415f17cSFelipe Balbi 
13507415f17cSFelipe Balbi static const struct dev_pm_ops dwc3_dev_pm_ops = {
13517415f17cSFelipe Balbi 	SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
1352fc8bb91bSFelipe Balbi 	SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume,
1353fc8bb91bSFelipe Balbi 			dwc3_runtime_idle)
13547415f17cSFelipe Balbi };
13557415f17cSFelipe Balbi 
13565088b6f5SKishon Vijay Abraham I #ifdef CONFIG_OF
13575088b6f5SKishon Vijay Abraham I static const struct of_device_id of_dwc3_match[] = {
13585088b6f5SKishon Vijay Abraham I 	{
135922a5aa17SFelipe Balbi 		.compatible = "snps,dwc3"
136022a5aa17SFelipe Balbi 	},
136122a5aa17SFelipe Balbi 	{
13625088b6f5SKishon Vijay Abraham I 		.compatible = "synopsys,dwc3"
13635088b6f5SKishon Vijay Abraham I 	},
13645088b6f5SKishon Vijay Abraham I 	{ },
13655088b6f5SKishon Vijay Abraham I };
13665088b6f5SKishon Vijay Abraham I MODULE_DEVICE_TABLE(of, of_dwc3_match);
13675088b6f5SKishon Vijay Abraham I #endif
13685088b6f5SKishon Vijay Abraham I 
1369404905a6SHeikki Krogerus #ifdef CONFIG_ACPI
1370404905a6SHeikki Krogerus 
1371404905a6SHeikki Krogerus #define ACPI_ID_INTEL_BSW	"808622B7"
1372404905a6SHeikki Krogerus 
1373404905a6SHeikki Krogerus static const struct acpi_device_id dwc3_acpi_match[] = {
1374404905a6SHeikki Krogerus 	{ ACPI_ID_INTEL_BSW, 0 },
1375404905a6SHeikki Krogerus 	{ },
1376404905a6SHeikki Krogerus };
1377404905a6SHeikki Krogerus MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match);
1378404905a6SHeikki Krogerus #endif
1379404905a6SHeikki Krogerus 
138072246da4SFelipe Balbi static struct platform_driver dwc3_driver = {
138172246da4SFelipe Balbi 	.probe		= dwc3_probe,
13827690417dSBill Pemberton 	.remove		= dwc3_remove,
138372246da4SFelipe Balbi 	.driver		= {
138472246da4SFelipe Balbi 		.name	= "dwc3",
13855088b6f5SKishon Vijay Abraham I 		.of_match_table	= of_match_ptr(of_dwc3_match),
1386404905a6SHeikki Krogerus 		.acpi_match_table = ACPI_PTR(dwc3_acpi_match),
13877f370ed0SFelipe Balbi 		.pm	= &dwc3_dev_pm_ops,
138872246da4SFelipe Balbi 	},
138972246da4SFelipe Balbi };
139072246da4SFelipe Balbi 
1391b1116dccSTobias Klauser module_platform_driver(dwc3_driver);
1392b1116dccSTobias Klauser 
13937ae4fc4dSSebastian Andrzej Siewior MODULE_ALIAS("platform:dwc3");
139472246da4SFelipe Balbi MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
13955945f789SFelipe Balbi MODULE_LICENSE("GPL v2");
139672246da4SFelipe Balbi MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
1397