xref: /openbmc/linux/drivers/usb/dwc3/core.c (revision a45c82b8)
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 
22a72e658bSFelipe Balbi #include <linux/module.h>
2372246da4SFelipe Balbi #include <linux/kernel.h>
2472246da4SFelipe Balbi #include <linux/slab.h>
2572246da4SFelipe Balbi #include <linux/spinlock.h>
2672246da4SFelipe Balbi #include <linux/platform_device.h>
2772246da4SFelipe Balbi #include <linux/pm_runtime.h>
2872246da4SFelipe Balbi #include <linux/interrupt.h>
2972246da4SFelipe Balbi #include <linux/ioport.h>
3072246da4SFelipe Balbi #include <linux/io.h>
3172246da4SFelipe Balbi #include <linux/list.h>
3272246da4SFelipe Balbi #include <linux/delay.h>
3372246da4SFelipe Balbi #include <linux/dma-mapping.h>
34457e84b6SFelipe Balbi #include <linux/of.h>
3572246da4SFelipe Balbi 
3651e1e7bcSFelipe Balbi #include <linux/usb/otg.h>
3772246da4SFelipe Balbi #include <linux/usb/ch9.h>
3872246da4SFelipe Balbi #include <linux/usb/gadget.h>
39f7e846f0SFelipe Balbi #include <linux/usb/of.h>
40a45c82b8SRuchika Kharwar #include <linux/usb/otg.h>
4172246da4SFelipe Balbi 
426462cbd5SFelipe Balbi #include "platform_data.h"
4372246da4SFelipe Balbi #include "core.h"
4472246da4SFelipe Balbi #include "gadget.h"
4572246da4SFelipe Balbi #include "io.h"
4672246da4SFelipe Balbi 
4772246da4SFelipe Balbi #include "debug.h"
4872246da4SFelipe Balbi 
498300dd23SFelipe Balbi /* -------------------------------------------------------------------------- */
508300dd23SFelipe Balbi 
513140e8cbSSebastian Andrzej Siewior void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
523140e8cbSSebastian Andrzej Siewior {
533140e8cbSSebastian Andrzej Siewior 	u32 reg;
543140e8cbSSebastian Andrzej Siewior 
553140e8cbSSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
563140e8cbSSebastian Andrzej Siewior 	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
573140e8cbSSebastian Andrzej Siewior 	reg |= DWC3_GCTL_PRTCAPDIR(mode);
583140e8cbSSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
593140e8cbSSebastian Andrzej Siewior }
608300dd23SFelipe Balbi 
6172246da4SFelipe Balbi /**
6272246da4SFelipe Balbi  * dwc3_core_soft_reset - Issues core soft reset and PHY reset
6372246da4SFelipe Balbi  * @dwc: pointer to our context structure
6472246da4SFelipe Balbi  */
6572246da4SFelipe Balbi static void dwc3_core_soft_reset(struct dwc3 *dwc)
6672246da4SFelipe Balbi {
6772246da4SFelipe Balbi 	u32		reg;
6872246da4SFelipe Balbi 
6972246da4SFelipe Balbi 	/* Before Resetting PHY, put Core in Reset */
7072246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
7172246da4SFelipe Balbi 	reg |= DWC3_GCTL_CORESOFTRESET;
7272246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
7372246da4SFelipe Balbi 
7472246da4SFelipe Balbi 	/* Assert USB3 PHY reset */
7572246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
7672246da4SFelipe Balbi 	reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
7772246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
7872246da4SFelipe Balbi 
7972246da4SFelipe Balbi 	/* Assert USB2 PHY reset */
8072246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
8172246da4SFelipe Balbi 	reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
8272246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
8372246da4SFelipe Balbi 
8451e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb2_phy);
8551e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb3_phy);
8672246da4SFelipe Balbi 	mdelay(100);
8772246da4SFelipe Balbi 
8872246da4SFelipe Balbi 	/* Clear USB3 PHY reset */
8972246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
9072246da4SFelipe Balbi 	reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
9172246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
9272246da4SFelipe Balbi 
9372246da4SFelipe Balbi 	/* Clear USB2 PHY reset */
9472246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
9572246da4SFelipe Balbi 	reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
9672246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
9772246da4SFelipe Balbi 
9845627ac6SPratyush Anand 	mdelay(100);
9945627ac6SPratyush Anand 
10072246da4SFelipe Balbi 	/* After PHYs are stable we can take Core out of reset state */
10172246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
10272246da4SFelipe Balbi 	reg &= ~DWC3_GCTL_CORESOFTRESET;
10372246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
10472246da4SFelipe Balbi }
10572246da4SFelipe Balbi 
10672246da4SFelipe Balbi /**
10772246da4SFelipe Balbi  * dwc3_free_one_event_buffer - Frees one event buffer
10872246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
10972246da4SFelipe Balbi  * @evt: Pointer to event buffer to be freed
11072246da4SFelipe Balbi  */
11172246da4SFelipe Balbi static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
11272246da4SFelipe Balbi 		struct dwc3_event_buffer *evt)
11372246da4SFelipe Balbi {
11472246da4SFelipe Balbi 	dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
11572246da4SFelipe Balbi }
11672246da4SFelipe Balbi 
11772246da4SFelipe Balbi /**
1181d046793SPaul Zimmerman  * dwc3_alloc_one_event_buffer - Allocates one event buffer structure
11972246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
12072246da4SFelipe Balbi  * @length: size of the event buffer
12172246da4SFelipe Balbi  *
1221d046793SPaul Zimmerman  * Returns a pointer to the allocated event buffer structure on success
12372246da4SFelipe Balbi  * otherwise ERR_PTR(errno).
12472246da4SFelipe Balbi  */
12567d0b500SFelipe Balbi static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
12667d0b500SFelipe Balbi 		unsigned length)
12772246da4SFelipe Balbi {
12872246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
12972246da4SFelipe Balbi 
130380f0d28SFelipe Balbi 	evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL);
13172246da4SFelipe Balbi 	if (!evt)
13272246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
13372246da4SFelipe Balbi 
13472246da4SFelipe Balbi 	evt->dwc	= dwc;
13572246da4SFelipe Balbi 	evt->length	= length;
13672246da4SFelipe Balbi 	evt->buf	= dma_alloc_coherent(dwc->dev, length,
13772246da4SFelipe Balbi 			&evt->dma, GFP_KERNEL);
138e32672f0SFelipe Balbi 	if (!evt->buf)
13972246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
14072246da4SFelipe Balbi 
14172246da4SFelipe Balbi 	return evt;
14272246da4SFelipe Balbi }
14372246da4SFelipe Balbi 
14472246da4SFelipe Balbi /**
14572246da4SFelipe Balbi  * dwc3_free_event_buffers - frees all allocated event buffers
14672246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
14772246da4SFelipe Balbi  */
14872246da4SFelipe Balbi static void dwc3_free_event_buffers(struct dwc3 *dwc)
14972246da4SFelipe Balbi {
15072246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
15172246da4SFelipe Balbi 	int i;
15272246da4SFelipe Balbi 
1539f622b2aSFelipe Balbi 	for (i = 0; i < dwc->num_event_buffers; i++) {
15472246da4SFelipe Balbi 		evt = dwc->ev_buffs[i];
15564b6c8a7SAnton Tikhomirov 		if (evt)
15672246da4SFelipe Balbi 			dwc3_free_one_event_buffer(dwc, evt);
15772246da4SFelipe Balbi 	}
15872246da4SFelipe Balbi }
15972246da4SFelipe Balbi 
16072246da4SFelipe Balbi /**
16172246da4SFelipe Balbi  * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
1621d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
16372246da4SFelipe Balbi  * @length: size of event buffer
16472246da4SFelipe Balbi  *
1651d046793SPaul Zimmerman  * Returns 0 on success otherwise negative errno. In the error case, dwc
16672246da4SFelipe Balbi  * may contain some buffers allocated but not all which were requested.
16772246da4SFelipe Balbi  */
16841ac7b3aSBill Pemberton static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
16972246da4SFelipe Balbi {
1709f622b2aSFelipe Balbi 	int			num;
17172246da4SFelipe Balbi 	int			i;
17272246da4SFelipe Balbi 
1739f622b2aSFelipe Balbi 	num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
1749f622b2aSFelipe Balbi 	dwc->num_event_buffers = num;
1759f622b2aSFelipe Balbi 
176380f0d28SFelipe Balbi 	dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num,
177380f0d28SFelipe Balbi 			GFP_KERNEL);
178457d3f21SFelipe Balbi 	if (!dwc->ev_buffs) {
179457d3f21SFelipe Balbi 		dev_err(dwc->dev, "can't allocate event buffers array\n");
180457d3f21SFelipe Balbi 		return -ENOMEM;
181457d3f21SFelipe Balbi 	}
182457d3f21SFelipe Balbi 
18372246da4SFelipe Balbi 	for (i = 0; i < num; i++) {
18472246da4SFelipe Balbi 		struct dwc3_event_buffer	*evt;
18572246da4SFelipe Balbi 
18672246da4SFelipe Balbi 		evt = dwc3_alloc_one_event_buffer(dwc, length);
18772246da4SFelipe Balbi 		if (IS_ERR(evt)) {
18872246da4SFelipe Balbi 			dev_err(dwc->dev, "can't allocate event buffer\n");
18972246da4SFelipe Balbi 			return PTR_ERR(evt);
19072246da4SFelipe Balbi 		}
19172246da4SFelipe Balbi 		dwc->ev_buffs[i] = evt;
19272246da4SFelipe Balbi 	}
19372246da4SFelipe Balbi 
19472246da4SFelipe Balbi 	return 0;
19572246da4SFelipe Balbi }
19672246da4SFelipe Balbi 
19772246da4SFelipe Balbi /**
19872246da4SFelipe Balbi  * dwc3_event_buffers_setup - setup our allocated event buffers
1991d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
20072246da4SFelipe Balbi  *
20172246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
20272246da4SFelipe Balbi  */
2037acd85e0SPaul Zimmerman static int dwc3_event_buffers_setup(struct dwc3 *dwc)
20472246da4SFelipe Balbi {
20572246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
20672246da4SFelipe Balbi 	int				n;
20772246da4SFelipe Balbi 
2089f622b2aSFelipe Balbi 	for (n = 0; n < dwc->num_event_buffers; n++) {
20972246da4SFelipe Balbi 		evt = dwc->ev_buffs[n];
21072246da4SFelipe Balbi 		dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
21172246da4SFelipe Balbi 				evt->buf, (unsigned long long) evt->dma,
21272246da4SFelipe Balbi 				evt->length);
21372246da4SFelipe Balbi 
2147acd85e0SPaul Zimmerman 		evt->lpos = 0;
2157acd85e0SPaul Zimmerman 
21672246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
21772246da4SFelipe Balbi 				lower_32_bits(evt->dma));
21872246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
21972246da4SFelipe Balbi 				upper_32_bits(evt->dma));
22072246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
22172246da4SFelipe Balbi 				evt->length & 0xffff);
22272246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
22372246da4SFelipe Balbi 	}
22472246da4SFelipe Balbi 
22572246da4SFelipe Balbi 	return 0;
22672246da4SFelipe Balbi }
22772246da4SFelipe Balbi 
22872246da4SFelipe Balbi static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
22972246da4SFelipe Balbi {
23072246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
23172246da4SFelipe Balbi 	int				n;
23272246da4SFelipe Balbi 
2339f622b2aSFelipe Balbi 	for (n = 0; n < dwc->num_event_buffers; n++) {
23472246da4SFelipe Balbi 		evt = dwc->ev_buffs[n];
2357acd85e0SPaul Zimmerman 
2367acd85e0SPaul Zimmerman 		evt->lpos = 0;
2377acd85e0SPaul Zimmerman 
23872246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
23972246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
24072246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
24172246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
24272246da4SFelipe Balbi 	}
24372246da4SFelipe Balbi }
24472246da4SFelipe Balbi 
245789451f6SFelipe Balbi static void dwc3_core_num_eps(struct dwc3 *dwc)
246789451f6SFelipe Balbi {
247789451f6SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
248789451f6SFelipe Balbi 
249789451f6SFelipe Balbi 	dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
250789451f6SFelipe Balbi 	dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
251789451f6SFelipe Balbi 
252789451f6SFelipe Balbi 	dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n",
253789451f6SFelipe Balbi 			dwc->num_in_eps, dwc->num_out_eps);
254789451f6SFelipe Balbi }
255789451f6SFelipe Balbi 
25641ac7b3aSBill Pemberton static void dwc3_cache_hwparams(struct dwc3 *dwc)
25726ceca97SFelipe Balbi {
25826ceca97SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
25926ceca97SFelipe Balbi 
26026ceca97SFelipe Balbi 	parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
26126ceca97SFelipe Balbi 	parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
26226ceca97SFelipe Balbi 	parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
26326ceca97SFelipe Balbi 	parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
26426ceca97SFelipe Balbi 	parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
26526ceca97SFelipe Balbi 	parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
26626ceca97SFelipe Balbi 	parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
26726ceca97SFelipe Balbi 	parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
26826ceca97SFelipe Balbi 	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
26926ceca97SFelipe Balbi }
27026ceca97SFelipe Balbi 
27172246da4SFelipe Balbi /**
27272246da4SFelipe Balbi  * dwc3_core_init - Low-level initialization of DWC3 Core
27372246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
27472246da4SFelipe Balbi  *
27572246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
27672246da4SFelipe Balbi  */
27741ac7b3aSBill Pemberton static int dwc3_core_init(struct dwc3 *dwc)
27872246da4SFelipe Balbi {
27972246da4SFelipe Balbi 	unsigned long		timeout;
28072246da4SFelipe Balbi 	u32			reg;
28172246da4SFelipe Balbi 	int			ret;
28272246da4SFelipe Balbi 
2837650bd74SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
2847650bd74SSebastian Andrzej Siewior 	/* This should read as U3 followed by revision number */
2857650bd74SSebastian Andrzej Siewior 	if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
2867650bd74SSebastian Andrzej Siewior 		dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
2877650bd74SSebastian Andrzej Siewior 		ret = -ENODEV;
2887650bd74SSebastian Andrzej Siewior 		goto err0;
2897650bd74SSebastian Andrzej Siewior 	}
290248b122bSFelipe Balbi 	dwc->revision = reg;
2917650bd74SSebastian Andrzej Siewior 
29272246da4SFelipe Balbi 	/* issue device SoftReset too */
29372246da4SFelipe Balbi 	timeout = jiffies + msecs_to_jiffies(500);
29472246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
29572246da4SFelipe Balbi 	do {
29672246da4SFelipe Balbi 		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
29772246da4SFelipe Balbi 		if (!(reg & DWC3_DCTL_CSFTRST))
29872246da4SFelipe Balbi 			break;
29972246da4SFelipe Balbi 
30072246da4SFelipe Balbi 		if (time_after(jiffies, timeout)) {
30172246da4SFelipe Balbi 			dev_err(dwc->dev, "Reset Timed Out\n");
30272246da4SFelipe Balbi 			ret = -ETIMEDOUT;
30372246da4SFelipe Balbi 			goto err0;
30472246da4SFelipe Balbi 		}
30572246da4SFelipe Balbi 
30672246da4SFelipe Balbi 		cpu_relax();
30772246da4SFelipe Balbi 	} while (true);
30872246da4SFelipe Balbi 
30958a0f23fSPratyush Anand 	dwc3_core_soft_reset(dwc);
31058a0f23fSPratyush Anand 
3114878a028SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
3123e87c42aSPaul Zimmerman 	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
3134878a028SSebastian Andrzej Siewior 	reg &= ~DWC3_GCTL_DISSCRAMBLE;
3144878a028SSebastian Andrzej Siewior 
315164d7731SSebastian Andrzej Siewior 	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
3164878a028SSebastian Andrzej Siewior 	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
3174878a028SSebastian Andrzej Siewior 		reg &= ~DWC3_GCTL_DSBLCLKGTNG;
3184878a028SSebastian Andrzej Siewior 		break;
3194878a028SSebastian Andrzej Siewior 	default:
3204878a028SSebastian Andrzej Siewior 		dev_dbg(dwc->dev, "No power optimization available\n");
3214878a028SSebastian Andrzej Siewior 	}
3224878a028SSebastian Andrzej Siewior 
3234878a028SSebastian Andrzej Siewior 	/*
3244878a028SSebastian Andrzej Siewior 	 * WORKAROUND: DWC3 revisions <1.90a have a bug
3251d046793SPaul Zimmerman 	 * where the device can fail to connect at SuperSpeed
3264878a028SSebastian Andrzej Siewior 	 * and falls back to high-speed mode which causes
3271d046793SPaul Zimmerman 	 * the device to enter a Connect/Disconnect loop
3284878a028SSebastian Andrzej Siewior 	 */
3294878a028SSebastian Andrzej Siewior 	if (dwc->revision < DWC3_REVISION_190A)
3304878a028SSebastian Andrzej Siewior 		reg |= DWC3_GCTL_U2RSTECN;
3314878a028SSebastian Andrzej Siewior 
332789451f6SFelipe Balbi 	dwc3_core_num_eps(dwc);
333789451f6SFelipe Balbi 
3344878a028SSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
3354878a028SSebastian Andrzej Siewior 
33672246da4SFelipe Balbi 	return 0;
33772246da4SFelipe Balbi 
33872246da4SFelipe Balbi err0:
33972246da4SFelipe Balbi 	return ret;
34072246da4SFelipe Balbi }
34172246da4SFelipe Balbi 
34272246da4SFelipe Balbi static void dwc3_core_exit(struct dwc3 *dwc)
34372246da4SFelipe Balbi {
34401b8daf7SVivek Gautam 	usb_phy_shutdown(dwc->usb2_phy);
34501b8daf7SVivek Gautam 	usb_phy_shutdown(dwc->usb3_phy);
34672246da4SFelipe Balbi }
34772246da4SFelipe Balbi 
34872246da4SFelipe Balbi #define DWC3_ALIGN_MASK		(16 - 1)
34972246da4SFelipe Balbi 
35041ac7b3aSBill Pemberton static int dwc3_probe(struct platform_device *pdev)
35172246da4SFelipe Balbi {
3526462cbd5SFelipe Balbi 	struct dwc3_platform_data *pdata = pdev->dev.platform_data;
353457e84b6SFelipe Balbi 	struct device_node	*node = pdev->dev.of_node;
35472246da4SFelipe Balbi 	struct resource		*res;
35572246da4SFelipe Balbi 	struct dwc3		*dwc;
356802ca850SChanho Park 	struct device		*dev = &pdev->dev;
3570949e99bSFelipe Balbi 
35872246da4SFelipe Balbi 	int			ret = -ENOMEM;
3590949e99bSFelipe Balbi 
3600949e99bSFelipe Balbi 	void __iomem		*regs;
36172246da4SFelipe Balbi 	void			*mem;
36272246da4SFelipe Balbi 
363802ca850SChanho Park 	mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
36472246da4SFelipe Balbi 	if (!mem) {
365802ca850SChanho Park 		dev_err(dev, "not enough memory\n");
366802ca850SChanho Park 		return -ENOMEM;
36772246da4SFelipe Balbi 	}
36872246da4SFelipe Balbi 	dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
36972246da4SFelipe Balbi 	dwc->mem = mem;
37072246da4SFelipe Balbi 
37151249dcaSIdo Shayevitz 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
37272246da4SFelipe Balbi 	if (!res) {
37351249dcaSIdo Shayevitz 		dev_err(dev, "missing IRQ\n");
374802ca850SChanho Park 		return -ENODEV;
37572246da4SFelipe Balbi 	}
376066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[1].start = res->start;
377066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[1].end = res->end;
378066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[1].flags = res->flags;
379066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[1].name = res->name;
38072246da4SFelipe Balbi 
38151249dcaSIdo Shayevitz 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
38251249dcaSIdo Shayevitz 	if (!res) {
38351249dcaSIdo Shayevitz 		dev_err(dev, "missing memory resource\n");
38451249dcaSIdo Shayevitz 		return -ENODEV;
38551249dcaSIdo Shayevitz 	}
386066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[0].start = res->start;
38751249dcaSIdo Shayevitz 	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
38851249dcaSIdo Shayevitz 					DWC3_XHCI_REGS_END;
389066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[0].flags = res->flags;
390066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[0].name = res->name;
391d07e8819SFelipe Balbi 
39251249dcaSIdo Shayevitz 	 /*
39351249dcaSIdo Shayevitz 	  * Request memory region but exclude xHCI regs,
39451249dcaSIdo Shayevitz 	  * since it will be requested by the xhci-plat driver.
39551249dcaSIdo Shayevitz 	  */
39651249dcaSIdo Shayevitz 	res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START,
39751249dcaSIdo Shayevitz 			resource_size(res) - DWC3_GLOBALS_REGS_START,
398802ca850SChanho Park 			dev_name(dev));
39972246da4SFelipe Balbi 	if (!res) {
400802ca850SChanho Park 		dev_err(dev, "can't request mem region\n");
401802ca850SChanho Park 		return -ENOMEM;
40272246da4SFelipe Balbi 	}
40372246da4SFelipe Balbi 
404b7e38aa6SFelipe Balbi 	regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
40572246da4SFelipe Balbi 	if (!regs) {
406802ca850SChanho Park 		dev_err(dev, "ioremap failed\n");
407802ca850SChanho Park 		return -ENOMEM;
40872246da4SFelipe Balbi 	}
40972246da4SFelipe Balbi 
4105088b6f5SKishon Vijay Abraham I 	if (node) {
411f7e846f0SFelipe Balbi 		dwc->maximum_speed = of_usb_get_maximum_speed(node);
412f7e846f0SFelipe Balbi 
4135088b6f5SKishon Vijay Abraham I 		dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
4145088b6f5SKishon Vijay Abraham I 		dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
4156462cbd5SFelipe Balbi 
4166462cbd5SFelipe Balbi 		dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
417a45c82b8SRuchika Kharwar 		dwc->dr_mode = of_usb_get_dr_mode(node);
4185088b6f5SKishon Vijay Abraham I 	} else {
419f7e846f0SFelipe Balbi 		dwc->maximum_speed = pdata->maximum_speed;
420f7e846f0SFelipe Balbi 
42151e1e7bcSFelipe Balbi 		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
4225088b6f5SKishon Vijay Abraham I 		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
4236462cbd5SFelipe Balbi 
4246462cbd5SFelipe Balbi 		dwc->needs_fifo_resize = pdata->tx_fifo_resize;
425a45c82b8SRuchika Kharwar 		dwc->dr_mode = pdata->dr_mode;
4265088b6f5SKishon Vijay Abraham I 	}
4275088b6f5SKishon Vijay Abraham I 
428f7e846f0SFelipe Balbi 	/* default to superspeed if no maximum_speed passed */
429f7e846f0SFelipe Balbi 	if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
430f7e846f0SFelipe Balbi 		dwc->maximum_speed = USB_SPEED_SUPER;
431f7e846f0SFelipe Balbi 
432d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb2_phy)) {
433d105e7f8SFelipe Balbi 		ret = PTR_ERR(dwc->usb2_phy);
434d105e7f8SFelipe Balbi 
435d105e7f8SFelipe Balbi 		/*
436d105e7f8SFelipe Balbi 		 * if -ENXIO is returned, it means PHY layer wasn't
437d105e7f8SFelipe Balbi 		 * enabled, so it makes no sense to return -EPROBE_DEFER
438d105e7f8SFelipe Balbi 		 * in that case, since no PHY driver will ever probe.
439d105e7f8SFelipe Balbi 		 */
440d105e7f8SFelipe Balbi 		if (ret == -ENXIO)
441d105e7f8SFelipe Balbi 			return ret;
442d105e7f8SFelipe Balbi 
44351e1e7bcSFelipe Balbi 		dev_err(dev, "no usb2 phy configured\n");
44451e1e7bcSFelipe Balbi 		return -EPROBE_DEFER;
44551e1e7bcSFelipe Balbi 	}
44651e1e7bcSFelipe Balbi 
447d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb3_phy)) {
448315955d7SRuchika Kharwar 		ret = PTR_ERR(dwc->usb3_phy);
449d105e7f8SFelipe Balbi 
450d105e7f8SFelipe Balbi 		/*
451d105e7f8SFelipe Balbi 		 * if -ENXIO is returned, it means PHY layer wasn't
452d105e7f8SFelipe Balbi 		 * enabled, so it makes no sense to return -EPROBE_DEFER
453d105e7f8SFelipe Balbi 		 * in that case, since no PHY driver will ever probe.
454d105e7f8SFelipe Balbi 		 */
455d105e7f8SFelipe Balbi 		if (ret == -ENXIO)
456d105e7f8SFelipe Balbi 			return ret;
457d105e7f8SFelipe Balbi 
45851e1e7bcSFelipe Balbi 		dev_err(dev, "no usb3 phy configured\n");
45951e1e7bcSFelipe Balbi 		return -EPROBE_DEFER;
46051e1e7bcSFelipe Balbi 	}
46151e1e7bcSFelipe Balbi 
4628ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 0);
4638ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 0);
4648ba007a9SKishon Vijay Abraham I 
46572246da4SFelipe Balbi 	spin_lock_init(&dwc->lock);
46672246da4SFelipe Balbi 	platform_set_drvdata(pdev, dwc);
46772246da4SFelipe Balbi 
46872246da4SFelipe Balbi 	dwc->regs	= regs;
46972246da4SFelipe Balbi 	dwc->regs_size	= resource_size(res);
470802ca850SChanho Park 	dwc->dev	= dev;
47172246da4SFelipe Balbi 
472ddff14f1SKishon Vijay Abraham I 	dev->dma_mask	= dev->parent->dma_mask;
473ddff14f1SKishon Vijay Abraham I 	dev->dma_parms	= dev->parent->dma_parms;
474ddff14f1SKishon Vijay Abraham I 	dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
475ddff14f1SKishon Vijay Abraham I 
476802ca850SChanho Park 	pm_runtime_enable(dev);
477802ca850SChanho Park 	pm_runtime_get_sync(dev);
478802ca850SChanho Park 	pm_runtime_forbid(dev);
47972246da4SFelipe Balbi 
4804fd24483SKishon Vijay Abraham I 	dwc3_cache_hwparams(dwc);
4814fd24483SKishon Vijay Abraham I 
4823921426bSFelipe Balbi 	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
4833921426bSFelipe Balbi 	if (ret) {
4843921426bSFelipe Balbi 		dev_err(dwc->dev, "failed to allocate event buffers\n");
4853921426bSFelipe Balbi 		ret = -ENOMEM;
4863921426bSFelipe Balbi 		goto err0;
4873921426bSFelipe Balbi 	}
4883921426bSFelipe Balbi 
48972246da4SFelipe Balbi 	ret = dwc3_core_init(dwc);
49072246da4SFelipe Balbi 	if (ret) {
491802ca850SChanho Park 		dev_err(dev, "failed to initialize core\n");
4923921426bSFelipe Balbi 		goto err0;
49372246da4SFelipe Balbi 	}
49472246da4SFelipe Balbi 
495f122d33eSFelipe Balbi 	ret = dwc3_event_buffers_setup(dwc);
496f122d33eSFelipe Balbi 	if (ret) {
497f122d33eSFelipe Balbi 		dev_err(dwc->dev, "failed to setup event buffers\n");
498f122d33eSFelipe Balbi 		goto err1;
499f122d33eSFelipe Balbi 	}
500f122d33eSFelipe Balbi 
501cd051da2SVivek Gautam 	if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
502a45c82b8SRuchika Kharwar 		dwc->dr_mode = USB_DR_MODE_HOST;
503cd051da2SVivek Gautam 	else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
504a45c82b8SRuchika Kharwar 		dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
5050949e99bSFelipe Balbi 
506a45c82b8SRuchika Kharwar 	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
507a45c82b8SRuchika Kharwar 		dwc->dr_mode = USB_DR_MODE_OTG;
508a45c82b8SRuchika Kharwar 
509a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
510a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
5113140e8cbSSebastian Andrzej Siewior 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
51272246da4SFelipe Balbi 		ret = dwc3_gadget_init(dwc);
51372246da4SFelipe Balbi 		if (ret) {
514802ca850SChanho Park 			dev_err(dev, "failed to initialize gadget\n");
515f122d33eSFelipe Balbi 			goto err2;
51672246da4SFelipe Balbi 		}
5170949e99bSFelipe Balbi 		break;
518a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
5193140e8cbSSebastian Andrzej Siewior 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
520d07e8819SFelipe Balbi 		ret = dwc3_host_init(dwc);
521d07e8819SFelipe Balbi 		if (ret) {
522802ca850SChanho Park 			dev_err(dev, "failed to initialize host\n");
523f122d33eSFelipe Balbi 			goto err2;
52472246da4SFelipe Balbi 		}
525d07e8819SFelipe Balbi 		break;
526a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
5273140e8cbSSebastian Andrzej Siewior 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
528d07e8819SFelipe Balbi 		ret = dwc3_host_init(dwc);
529d07e8819SFelipe Balbi 		if (ret) {
530802ca850SChanho Park 			dev_err(dev, "failed to initialize host\n");
531f122d33eSFelipe Balbi 			goto err2;
532d07e8819SFelipe Balbi 		}
533d07e8819SFelipe Balbi 
534d07e8819SFelipe Balbi 		ret = dwc3_gadget_init(dwc);
535d07e8819SFelipe Balbi 		if (ret) {
536802ca850SChanho Park 			dev_err(dev, "failed to initialize gadget\n");
537f122d33eSFelipe Balbi 			goto err2;
538d07e8819SFelipe Balbi 		}
539d07e8819SFelipe Balbi 		break;
5400949e99bSFelipe Balbi 	default:
541a45c82b8SRuchika Kharwar 		dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
542f122d33eSFelipe Balbi 		goto err2;
54372246da4SFelipe Balbi 	}
54472246da4SFelipe Balbi 
54572246da4SFelipe Balbi 	ret = dwc3_debugfs_init(dwc);
54672246da4SFelipe Balbi 	if (ret) {
547802ca850SChanho Park 		dev_err(dev, "failed to initialize debugfs\n");
548f122d33eSFelipe Balbi 		goto err3;
54972246da4SFelipe Balbi 	}
55072246da4SFelipe Balbi 
551802ca850SChanho Park 	pm_runtime_allow(dev);
55272246da4SFelipe Balbi 
55372246da4SFelipe Balbi 	return 0;
55472246da4SFelipe Balbi 
555f122d33eSFelipe Balbi err3:
556a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
557a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
55872246da4SFelipe Balbi 		dwc3_gadget_exit(dwc);
5590949e99bSFelipe Balbi 		break;
560a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
561d07e8819SFelipe Balbi 		dwc3_host_exit(dwc);
562d07e8819SFelipe Balbi 		break;
563a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
564d07e8819SFelipe Balbi 		dwc3_host_exit(dwc);
565d07e8819SFelipe Balbi 		dwc3_gadget_exit(dwc);
566d07e8819SFelipe Balbi 		break;
5670949e99bSFelipe Balbi 	default:
5680949e99bSFelipe Balbi 		/* do nothing */
5690949e99bSFelipe Balbi 		break;
5700949e99bSFelipe Balbi 	}
57172246da4SFelipe Balbi 
572f122d33eSFelipe Balbi err2:
573f122d33eSFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
574f122d33eSFelipe Balbi 
575802ca850SChanho Park err1:
57672246da4SFelipe Balbi 	dwc3_core_exit(dwc);
57772246da4SFelipe Balbi 
5783921426bSFelipe Balbi err0:
5793921426bSFelipe Balbi 	dwc3_free_event_buffers(dwc);
5803921426bSFelipe Balbi 
58172246da4SFelipe Balbi 	return ret;
58272246da4SFelipe Balbi }
58372246da4SFelipe Balbi 
584fb4e98abSBill Pemberton static int dwc3_remove(struct platform_device *pdev)
58572246da4SFelipe Balbi {
58672246da4SFelipe Balbi 	struct dwc3	*dwc = platform_get_drvdata(pdev);
58772246da4SFelipe Balbi 
5888ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 1);
5898ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 1);
5908ba007a9SKishon Vijay Abraham I 
59172246da4SFelipe Balbi 	pm_runtime_put(&pdev->dev);
59272246da4SFelipe Balbi 	pm_runtime_disable(&pdev->dev);
59372246da4SFelipe Balbi 
59472246da4SFelipe Balbi 	dwc3_debugfs_exit(dwc);
59572246da4SFelipe Balbi 
596a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
597a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
59872246da4SFelipe Balbi 		dwc3_gadget_exit(dwc);
5990949e99bSFelipe Balbi 		break;
600a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
601d07e8819SFelipe Balbi 		dwc3_host_exit(dwc);
602d07e8819SFelipe Balbi 		break;
603a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
604d07e8819SFelipe Balbi 		dwc3_host_exit(dwc);
605d07e8819SFelipe Balbi 		dwc3_gadget_exit(dwc);
606d07e8819SFelipe Balbi 		break;
6070949e99bSFelipe Balbi 	default:
6080949e99bSFelipe Balbi 		/* do nothing */
6090949e99bSFelipe Balbi 		break;
6100949e99bSFelipe Balbi 	}
61172246da4SFelipe Balbi 
612f122d33eSFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
613d9b4330aSFelipe Balbi 	dwc3_free_event_buffers(dwc);
61472246da4SFelipe Balbi 	dwc3_core_exit(dwc);
61572246da4SFelipe Balbi 
61672246da4SFelipe Balbi 	return 0;
61772246da4SFelipe Balbi }
61872246da4SFelipe Balbi 
61919fda7cdSJingoo Han #ifdef CONFIG_PM_SLEEP
6207415f17cSFelipe Balbi static int dwc3_prepare(struct device *dev)
6217415f17cSFelipe Balbi {
6227415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
6237415f17cSFelipe Balbi 	unsigned long	flags;
6247415f17cSFelipe Balbi 
6257415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
6267415f17cSFelipe Balbi 
627a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
628a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
629a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
6307415f17cSFelipe Balbi 		dwc3_gadget_prepare(dwc);
6317415f17cSFelipe Balbi 		/* FALLTHROUGH */
632a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
6337415f17cSFelipe Balbi 	default:
6347415f17cSFelipe Balbi 		dwc3_event_buffers_cleanup(dwc);
6357415f17cSFelipe Balbi 		break;
6367415f17cSFelipe Balbi 	}
6377415f17cSFelipe Balbi 
6387415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
6397415f17cSFelipe Balbi 
6407415f17cSFelipe Balbi 	return 0;
6417415f17cSFelipe Balbi }
6427415f17cSFelipe Balbi 
6437415f17cSFelipe Balbi static void dwc3_complete(struct device *dev)
6447415f17cSFelipe Balbi {
6457415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
6467415f17cSFelipe Balbi 	unsigned long	flags;
6477415f17cSFelipe Balbi 
6487415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
6497415f17cSFelipe Balbi 
650a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
651a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
652a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
6537415f17cSFelipe Balbi 		dwc3_gadget_complete(dwc);
6547415f17cSFelipe Balbi 		/* FALLTHROUGH */
655a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
6567415f17cSFelipe Balbi 	default:
6577415f17cSFelipe Balbi 		dwc3_event_buffers_setup(dwc);
6587415f17cSFelipe Balbi 		break;
6597415f17cSFelipe Balbi 	}
6607415f17cSFelipe Balbi 
6617415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
6627415f17cSFelipe Balbi }
6637415f17cSFelipe Balbi 
6647415f17cSFelipe Balbi static int dwc3_suspend(struct device *dev)
6657415f17cSFelipe Balbi {
6667415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
6677415f17cSFelipe Balbi 	unsigned long	flags;
6687415f17cSFelipe Balbi 
6697415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
6707415f17cSFelipe Balbi 
671a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
672a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
673a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
6747415f17cSFelipe Balbi 		dwc3_gadget_suspend(dwc);
6757415f17cSFelipe Balbi 		/* FALLTHROUGH */
676a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
6777415f17cSFelipe Balbi 	default:
6787415f17cSFelipe Balbi 		/* do nothing */
6797415f17cSFelipe Balbi 		break;
6807415f17cSFelipe Balbi 	}
6817415f17cSFelipe Balbi 
6827415f17cSFelipe Balbi 	dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL);
6837415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
6847415f17cSFelipe Balbi 
6857415f17cSFelipe Balbi 	usb_phy_shutdown(dwc->usb3_phy);
6867415f17cSFelipe Balbi 	usb_phy_shutdown(dwc->usb2_phy);
6877415f17cSFelipe Balbi 
6887415f17cSFelipe Balbi 	return 0;
6897415f17cSFelipe Balbi }
6907415f17cSFelipe Balbi 
6917415f17cSFelipe Balbi static int dwc3_resume(struct device *dev)
6927415f17cSFelipe Balbi {
6937415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
6947415f17cSFelipe Balbi 	unsigned long	flags;
6957415f17cSFelipe Balbi 
6967415f17cSFelipe Balbi 	usb_phy_init(dwc->usb3_phy);
6977415f17cSFelipe Balbi 	usb_phy_init(dwc->usb2_phy);
6987415f17cSFelipe Balbi 	msleep(100);
6997415f17cSFelipe Balbi 
7007415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
7017415f17cSFelipe Balbi 
7027415f17cSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
7037415f17cSFelipe Balbi 
704a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
705a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
706a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
7077415f17cSFelipe Balbi 		dwc3_gadget_resume(dwc);
7087415f17cSFelipe Balbi 		/* FALLTHROUGH */
709a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
7107415f17cSFelipe Balbi 	default:
7117415f17cSFelipe Balbi 		/* do nothing */
7127415f17cSFelipe Balbi 		break;
7137415f17cSFelipe Balbi 	}
7147415f17cSFelipe Balbi 
7157415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
7167415f17cSFelipe Balbi 
7177415f17cSFelipe Balbi 	pm_runtime_disable(dev);
7187415f17cSFelipe Balbi 	pm_runtime_set_active(dev);
7197415f17cSFelipe Balbi 	pm_runtime_enable(dev);
7207415f17cSFelipe Balbi 
7217415f17cSFelipe Balbi 	return 0;
7227415f17cSFelipe Balbi }
7237415f17cSFelipe Balbi 
7247415f17cSFelipe Balbi static const struct dev_pm_ops dwc3_dev_pm_ops = {
7257415f17cSFelipe Balbi 	.prepare	= dwc3_prepare,
7267415f17cSFelipe Balbi 	.complete	= dwc3_complete,
7277415f17cSFelipe Balbi 
7287415f17cSFelipe Balbi 	SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
7297415f17cSFelipe Balbi };
7307415f17cSFelipe Balbi 
7317415f17cSFelipe Balbi #define DWC3_PM_OPS	&(dwc3_dev_pm_ops)
7327415f17cSFelipe Balbi #else
7337415f17cSFelipe Balbi #define DWC3_PM_OPS	NULL
7347415f17cSFelipe Balbi #endif
7357415f17cSFelipe Balbi 
7365088b6f5SKishon Vijay Abraham I #ifdef CONFIG_OF
7375088b6f5SKishon Vijay Abraham I static const struct of_device_id of_dwc3_match[] = {
7385088b6f5SKishon Vijay Abraham I 	{
73922a5aa17SFelipe Balbi 		.compatible = "snps,dwc3"
74022a5aa17SFelipe Balbi 	},
74122a5aa17SFelipe Balbi 	{
7425088b6f5SKishon Vijay Abraham I 		.compatible = "synopsys,dwc3"
7435088b6f5SKishon Vijay Abraham I 	},
7445088b6f5SKishon Vijay Abraham I 	{ },
7455088b6f5SKishon Vijay Abraham I };
7465088b6f5SKishon Vijay Abraham I MODULE_DEVICE_TABLE(of, of_dwc3_match);
7475088b6f5SKishon Vijay Abraham I #endif
7485088b6f5SKishon Vijay Abraham I 
74972246da4SFelipe Balbi static struct platform_driver dwc3_driver = {
75072246da4SFelipe Balbi 	.probe		= dwc3_probe,
7517690417dSBill Pemberton 	.remove		= dwc3_remove,
75272246da4SFelipe Balbi 	.driver		= {
75372246da4SFelipe Balbi 		.name	= "dwc3",
7545088b6f5SKishon Vijay Abraham I 		.of_match_table	= of_match_ptr(of_dwc3_match),
7557415f17cSFelipe Balbi 		.pm	= DWC3_PM_OPS,
75672246da4SFelipe Balbi 	},
75772246da4SFelipe Balbi };
75872246da4SFelipe Balbi 
759b1116dccSTobias Klauser module_platform_driver(dwc3_driver);
760b1116dccSTobias Klauser 
7617ae4fc4dSSebastian Andrzej Siewior MODULE_ALIAS("platform:dwc3");
76272246da4SFelipe Balbi MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
7635945f789SFelipe Balbi MODULE_LICENSE("GPL v2");
76472246da4SFelipe Balbi MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
765