xref: /openbmc/linux/drivers/usb/dwc3/core.c (revision 3088f108)
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 
3672246da4SFelipe Balbi #include <linux/usb/ch9.h>
3772246da4SFelipe Balbi #include <linux/usb/gadget.h>
38f7e846f0SFelipe Balbi #include <linux/usb/of.h>
39a45c82b8SRuchika Kharwar #include <linux/usb/otg.h>
4072246da4SFelipe Balbi 
416462cbd5SFelipe Balbi #include "platform_data.h"
4272246da4SFelipe Balbi #include "core.h"
4372246da4SFelipe Balbi #include "gadget.h"
4472246da4SFelipe Balbi #include "io.h"
4572246da4SFelipe Balbi 
4672246da4SFelipe Balbi #include "debug.h"
4772246da4SFelipe Balbi 
488300dd23SFelipe Balbi /* -------------------------------------------------------------------------- */
498300dd23SFelipe Balbi 
503140e8cbSSebastian Andrzej Siewior void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
513140e8cbSSebastian Andrzej Siewior {
523140e8cbSSebastian Andrzej Siewior 	u32 reg;
533140e8cbSSebastian Andrzej Siewior 
543140e8cbSSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
553140e8cbSSebastian Andrzej Siewior 	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
563140e8cbSSebastian Andrzej Siewior 	reg |= DWC3_GCTL_PRTCAPDIR(mode);
573140e8cbSSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
583140e8cbSSebastian Andrzej Siewior }
598300dd23SFelipe Balbi 
6072246da4SFelipe Balbi /**
6172246da4SFelipe Balbi  * dwc3_core_soft_reset - Issues core soft reset and PHY reset
6272246da4SFelipe Balbi  * @dwc: pointer to our context structure
6372246da4SFelipe Balbi  */
6472246da4SFelipe Balbi static void dwc3_core_soft_reset(struct dwc3 *dwc)
6572246da4SFelipe Balbi {
6672246da4SFelipe Balbi 	u32		reg;
6772246da4SFelipe Balbi 
6872246da4SFelipe Balbi 	/* Before Resetting PHY, put Core in Reset */
6972246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
7072246da4SFelipe Balbi 	reg |= DWC3_GCTL_CORESOFTRESET;
7172246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
7272246da4SFelipe Balbi 
7372246da4SFelipe Balbi 	/* Assert USB3 PHY reset */
7472246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
7572246da4SFelipe Balbi 	reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
7672246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
7772246da4SFelipe Balbi 
7872246da4SFelipe Balbi 	/* Assert USB2 PHY reset */
7972246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
8072246da4SFelipe Balbi 	reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
8172246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
8272246da4SFelipe Balbi 
8351e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb2_phy);
8451e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb3_phy);
8572246da4SFelipe Balbi 	mdelay(100);
8672246da4SFelipe Balbi 
8772246da4SFelipe Balbi 	/* Clear USB3 PHY reset */
8872246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
8972246da4SFelipe Balbi 	reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
9072246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
9172246da4SFelipe Balbi 
9272246da4SFelipe Balbi 	/* Clear USB2 PHY reset */
9372246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
9472246da4SFelipe Balbi 	reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
9572246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
9672246da4SFelipe Balbi 
9745627ac6SPratyush Anand 	mdelay(100);
9845627ac6SPratyush Anand 
9972246da4SFelipe Balbi 	/* After PHYs are stable we can take Core out of reset state */
10072246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
10172246da4SFelipe Balbi 	reg &= ~DWC3_GCTL_CORESOFTRESET;
10272246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
10372246da4SFelipe Balbi }
10472246da4SFelipe Balbi 
10572246da4SFelipe Balbi /**
10672246da4SFelipe Balbi  * dwc3_free_one_event_buffer - Frees one event buffer
10772246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
10872246da4SFelipe Balbi  * @evt: Pointer to event buffer to be freed
10972246da4SFelipe Balbi  */
11072246da4SFelipe Balbi static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
11172246da4SFelipe Balbi 		struct dwc3_event_buffer *evt)
11272246da4SFelipe Balbi {
11372246da4SFelipe Balbi 	dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
11472246da4SFelipe Balbi }
11572246da4SFelipe Balbi 
11672246da4SFelipe Balbi /**
1171d046793SPaul Zimmerman  * dwc3_alloc_one_event_buffer - Allocates one event buffer structure
11872246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
11972246da4SFelipe Balbi  * @length: size of the event buffer
12072246da4SFelipe Balbi  *
1211d046793SPaul Zimmerman  * Returns a pointer to the allocated event buffer structure on success
12272246da4SFelipe Balbi  * otherwise ERR_PTR(errno).
12372246da4SFelipe Balbi  */
12467d0b500SFelipe Balbi static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
12567d0b500SFelipe Balbi 		unsigned length)
12672246da4SFelipe Balbi {
12772246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
12872246da4SFelipe Balbi 
129380f0d28SFelipe Balbi 	evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL);
13072246da4SFelipe Balbi 	if (!evt)
13172246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
13272246da4SFelipe Balbi 
13372246da4SFelipe Balbi 	evt->dwc	= dwc;
13472246da4SFelipe Balbi 	evt->length	= length;
13572246da4SFelipe Balbi 	evt->buf	= dma_alloc_coherent(dwc->dev, length,
13672246da4SFelipe Balbi 			&evt->dma, GFP_KERNEL);
137e32672f0SFelipe Balbi 	if (!evt->buf)
13872246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
13972246da4SFelipe Balbi 
14072246da4SFelipe Balbi 	return evt;
14172246da4SFelipe Balbi }
14272246da4SFelipe Balbi 
14372246da4SFelipe Balbi /**
14472246da4SFelipe Balbi  * dwc3_free_event_buffers - frees all allocated event buffers
14572246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
14672246da4SFelipe Balbi  */
14772246da4SFelipe Balbi static void dwc3_free_event_buffers(struct dwc3 *dwc)
14872246da4SFelipe Balbi {
14972246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
15072246da4SFelipe Balbi 	int i;
15172246da4SFelipe Balbi 
1529f622b2aSFelipe Balbi 	for (i = 0; i < dwc->num_event_buffers; i++) {
15372246da4SFelipe Balbi 		evt = dwc->ev_buffs[i];
15464b6c8a7SAnton Tikhomirov 		if (evt)
15572246da4SFelipe Balbi 			dwc3_free_one_event_buffer(dwc, evt);
15672246da4SFelipe Balbi 	}
15772246da4SFelipe Balbi }
15872246da4SFelipe Balbi 
15972246da4SFelipe Balbi /**
16072246da4SFelipe Balbi  * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
1611d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
16272246da4SFelipe Balbi  * @length: size of event buffer
16372246da4SFelipe Balbi  *
1641d046793SPaul Zimmerman  * Returns 0 on success otherwise negative errno. In the error case, dwc
16572246da4SFelipe Balbi  * may contain some buffers allocated but not all which were requested.
16672246da4SFelipe Balbi  */
16741ac7b3aSBill Pemberton static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
16872246da4SFelipe Balbi {
1699f622b2aSFelipe Balbi 	int			num;
17072246da4SFelipe Balbi 	int			i;
17172246da4SFelipe Balbi 
1729f622b2aSFelipe Balbi 	num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
1739f622b2aSFelipe Balbi 	dwc->num_event_buffers = num;
1749f622b2aSFelipe Balbi 
175380f0d28SFelipe Balbi 	dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num,
176380f0d28SFelipe Balbi 			GFP_KERNEL);
177457d3f21SFelipe Balbi 	if (!dwc->ev_buffs) {
178457d3f21SFelipe Balbi 		dev_err(dwc->dev, "can't allocate event buffers array\n");
179457d3f21SFelipe Balbi 		return -ENOMEM;
180457d3f21SFelipe Balbi 	}
181457d3f21SFelipe Balbi 
18272246da4SFelipe Balbi 	for (i = 0; i < num; i++) {
18372246da4SFelipe Balbi 		struct dwc3_event_buffer	*evt;
18472246da4SFelipe Balbi 
18572246da4SFelipe Balbi 		evt = dwc3_alloc_one_event_buffer(dwc, length);
18672246da4SFelipe Balbi 		if (IS_ERR(evt)) {
18772246da4SFelipe Balbi 			dev_err(dwc->dev, "can't allocate event buffer\n");
18872246da4SFelipe Balbi 			return PTR_ERR(evt);
18972246da4SFelipe Balbi 		}
19072246da4SFelipe Balbi 		dwc->ev_buffs[i] = evt;
19172246da4SFelipe Balbi 	}
19272246da4SFelipe Balbi 
19372246da4SFelipe Balbi 	return 0;
19472246da4SFelipe Balbi }
19572246da4SFelipe Balbi 
19672246da4SFelipe Balbi /**
19772246da4SFelipe Balbi  * dwc3_event_buffers_setup - setup our allocated event buffers
1981d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
19972246da4SFelipe Balbi  *
20072246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
20172246da4SFelipe Balbi  */
2027acd85e0SPaul Zimmerman static int dwc3_event_buffers_setup(struct dwc3 *dwc)
20372246da4SFelipe Balbi {
20472246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
20572246da4SFelipe Balbi 	int				n;
20672246da4SFelipe Balbi 
2079f622b2aSFelipe Balbi 	for (n = 0; n < dwc->num_event_buffers; n++) {
20872246da4SFelipe Balbi 		evt = dwc->ev_buffs[n];
20972246da4SFelipe Balbi 		dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
21072246da4SFelipe Balbi 				evt->buf, (unsigned long long) evt->dma,
21172246da4SFelipe Balbi 				evt->length);
21272246da4SFelipe Balbi 
2137acd85e0SPaul Zimmerman 		evt->lpos = 0;
2147acd85e0SPaul Zimmerman 
21572246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
21672246da4SFelipe Balbi 				lower_32_bits(evt->dma));
21772246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
21872246da4SFelipe Balbi 				upper_32_bits(evt->dma));
21972246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
22068d6a01bSFelipe Balbi 				DWC3_GEVNTSIZ_SIZE(evt->length));
22172246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
22272246da4SFelipe Balbi 	}
22372246da4SFelipe Balbi 
22472246da4SFelipe Balbi 	return 0;
22572246da4SFelipe Balbi }
22672246da4SFelipe Balbi 
22772246da4SFelipe Balbi static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
22872246da4SFelipe Balbi {
22972246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
23072246da4SFelipe Balbi 	int				n;
23172246da4SFelipe Balbi 
2329f622b2aSFelipe Balbi 	for (n = 0; n < dwc->num_event_buffers; n++) {
23372246da4SFelipe Balbi 		evt = dwc->ev_buffs[n];
2347acd85e0SPaul Zimmerman 
2357acd85e0SPaul Zimmerman 		evt->lpos = 0;
2367acd85e0SPaul Zimmerman 
23772246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
23872246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
23968d6a01bSFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK
24068d6a01bSFelipe Balbi 				| DWC3_GEVNTSIZ_SIZE(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 {
352941ea361SFelipe Balbi 	struct device		*dev = &pdev->dev;
353941ea361SFelipe Balbi 	struct dwc3_platform_data *pdata = dev_get_platdata(dev);
354941ea361SFelipe Balbi 	struct device_node	*node = dev->of_node;
35572246da4SFelipe Balbi 	struct resource		*res;
35672246da4SFelipe Balbi 	struct dwc3		*dwc;
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 	}
38672246da4SFelipe Balbi 
3875088b6f5SKishon Vijay Abraham I 	if (node) {
388f7e846f0SFelipe Balbi 		dwc->maximum_speed = of_usb_get_maximum_speed(node);
389f7e846f0SFelipe Balbi 
3905088b6f5SKishon Vijay Abraham I 		dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
3915088b6f5SKishon Vijay Abraham I 		dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
3926462cbd5SFelipe Balbi 
3936462cbd5SFelipe Balbi 		dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
394a45c82b8SRuchika Kharwar 		dwc->dr_mode = of_usb_get_dr_mode(node);
395bb674907SFelipe Balbi 	} else if (pdata) {
396f7e846f0SFelipe Balbi 		dwc->maximum_speed = pdata->maximum_speed;
397f7e846f0SFelipe Balbi 
39851e1e7bcSFelipe Balbi 		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
3995088b6f5SKishon Vijay Abraham I 		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
4006462cbd5SFelipe Balbi 
4016462cbd5SFelipe Balbi 		dwc->needs_fifo_resize = pdata->tx_fifo_resize;
402a45c82b8SRuchika Kharwar 		dwc->dr_mode = pdata->dr_mode;
403bb674907SFelipe Balbi 	} else {
404bb674907SFelipe Balbi 		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
405bb674907SFelipe Balbi 		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
4065088b6f5SKishon Vijay Abraham I 	}
4075088b6f5SKishon Vijay Abraham I 
408f7e846f0SFelipe Balbi 	/* default to superspeed if no maximum_speed passed */
409f7e846f0SFelipe Balbi 	if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
410f7e846f0SFelipe Balbi 		dwc->maximum_speed = USB_SPEED_SUPER;
411f7e846f0SFelipe Balbi 
412d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb2_phy)) {
413d105e7f8SFelipe Balbi 		ret = PTR_ERR(dwc->usb2_phy);
414d105e7f8SFelipe Balbi 
415d105e7f8SFelipe Balbi 		/*
416d105e7f8SFelipe Balbi 		 * if -ENXIO is returned, it means PHY layer wasn't
417d105e7f8SFelipe Balbi 		 * enabled, so it makes no sense to return -EPROBE_DEFER
418d105e7f8SFelipe Balbi 		 * in that case, since no PHY driver will ever probe.
419d105e7f8SFelipe Balbi 		 */
420d105e7f8SFelipe Balbi 		if (ret == -ENXIO)
421d105e7f8SFelipe Balbi 			return ret;
422d105e7f8SFelipe Balbi 
42351e1e7bcSFelipe Balbi 		dev_err(dev, "no usb2 phy configured\n");
42451e1e7bcSFelipe Balbi 		return -EPROBE_DEFER;
42551e1e7bcSFelipe Balbi 	}
42651e1e7bcSFelipe Balbi 
427d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb3_phy)) {
428315955d7SRuchika Kharwar 		ret = PTR_ERR(dwc->usb3_phy);
429d105e7f8SFelipe Balbi 
430d105e7f8SFelipe Balbi 		/*
431d105e7f8SFelipe Balbi 		 * if -ENXIO is returned, it means PHY layer wasn't
432d105e7f8SFelipe Balbi 		 * enabled, so it makes no sense to return -EPROBE_DEFER
433d105e7f8SFelipe Balbi 		 * in that case, since no PHY driver will ever probe.
434d105e7f8SFelipe Balbi 		 */
435d105e7f8SFelipe Balbi 		if (ret == -ENXIO)
436d105e7f8SFelipe Balbi 			return ret;
437d105e7f8SFelipe Balbi 
43851e1e7bcSFelipe Balbi 		dev_err(dev, "no usb3 phy configured\n");
43951e1e7bcSFelipe Balbi 		return -EPROBE_DEFER;
44051e1e7bcSFelipe Balbi 	}
44151e1e7bcSFelipe Balbi 
4422e112345SIvan T. Ivanov 	dwc->xhci_resources[0].start = res->start;
4432e112345SIvan T. Ivanov 	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
4442e112345SIvan T. Ivanov 					DWC3_XHCI_REGS_END;
4452e112345SIvan T. Ivanov 	dwc->xhci_resources[0].flags = res->flags;
4462e112345SIvan T. Ivanov 	dwc->xhci_resources[0].name = res->name;
4472e112345SIvan T. Ivanov 
4482e112345SIvan T. Ivanov 	res->start += DWC3_GLOBALS_REGS_START;
4492e112345SIvan T. Ivanov 
4502e112345SIvan T. Ivanov 	/*
4512e112345SIvan T. Ivanov 	 * Request memory region but exclude xHCI regs,
4522e112345SIvan T. Ivanov 	 * since it will be requested by the xhci-plat driver.
4532e112345SIvan T. Ivanov 	 */
4542e112345SIvan T. Ivanov 	regs = devm_ioremap_resource(dev, res);
4552e112345SIvan T. Ivanov 	if (IS_ERR(regs))
4562e112345SIvan T. Ivanov 		return PTR_ERR(regs);
4572e112345SIvan T. Ivanov 
45872246da4SFelipe Balbi 	spin_lock_init(&dwc->lock);
45972246da4SFelipe Balbi 	platform_set_drvdata(pdev, dwc);
46072246da4SFelipe Balbi 
46172246da4SFelipe Balbi 	dwc->regs	= regs;
46272246da4SFelipe Balbi 	dwc->regs_size	= resource_size(res);
463802ca850SChanho Park 	dwc->dev	= dev;
46472246da4SFelipe Balbi 
465ddff14f1SKishon Vijay Abraham I 	dev->dma_mask	= dev->parent->dma_mask;
466ddff14f1SKishon Vijay Abraham I 	dev->dma_parms	= dev->parent->dma_parms;
467ddff14f1SKishon Vijay Abraham I 	dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
468ddff14f1SKishon Vijay Abraham I 
469802ca850SChanho Park 	pm_runtime_enable(dev);
470802ca850SChanho Park 	pm_runtime_get_sync(dev);
471802ca850SChanho Park 	pm_runtime_forbid(dev);
47272246da4SFelipe Balbi 
4734fd24483SKishon Vijay Abraham I 	dwc3_cache_hwparams(dwc);
4744fd24483SKishon Vijay Abraham I 
4753921426bSFelipe Balbi 	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
4763921426bSFelipe Balbi 	if (ret) {
4773921426bSFelipe Balbi 		dev_err(dwc->dev, "failed to allocate event buffers\n");
4783921426bSFelipe Balbi 		ret = -ENOMEM;
4793921426bSFelipe Balbi 		goto err0;
4803921426bSFelipe Balbi 	}
4813921426bSFelipe Balbi 
48272246da4SFelipe Balbi 	ret = dwc3_core_init(dwc);
48372246da4SFelipe Balbi 	if (ret) {
484802ca850SChanho Park 		dev_err(dev, "failed to initialize core\n");
4853921426bSFelipe Balbi 		goto err0;
48672246da4SFelipe Balbi 	}
48772246da4SFelipe Balbi 
4883088f108SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 0);
4893088f108SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 0);
4903088f108SKishon Vijay Abraham I 
491f122d33eSFelipe Balbi 	ret = dwc3_event_buffers_setup(dwc);
492f122d33eSFelipe Balbi 	if (ret) {
493f122d33eSFelipe Balbi 		dev_err(dwc->dev, "failed to setup event buffers\n");
494f122d33eSFelipe Balbi 		goto err1;
495f122d33eSFelipe Balbi 	}
496f122d33eSFelipe Balbi 
497cd051da2SVivek Gautam 	if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
498a45c82b8SRuchika Kharwar 		dwc->dr_mode = USB_DR_MODE_HOST;
499cd051da2SVivek Gautam 	else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
500a45c82b8SRuchika Kharwar 		dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
5010949e99bSFelipe Balbi 
502a45c82b8SRuchika Kharwar 	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
503a45c82b8SRuchika Kharwar 		dwc->dr_mode = USB_DR_MODE_OTG;
504a45c82b8SRuchika Kharwar 
505a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
506a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
5073140e8cbSSebastian Andrzej Siewior 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
50872246da4SFelipe Balbi 		ret = dwc3_gadget_init(dwc);
50972246da4SFelipe Balbi 		if (ret) {
510802ca850SChanho Park 			dev_err(dev, "failed to initialize gadget\n");
511f122d33eSFelipe Balbi 			goto err2;
51272246da4SFelipe Balbi 		}
5130949e99bSFelipe Balbi 		break;
514a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
5153140e8cbSSebastian Andrzej Siewior 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
516d07e8819SFelipe Balbi 		ret = dwc3_host_init(dwc);
517d07e8819SFelipe Balbi 		if (ret) {
518802ca850SChanho Park 			dev_err(dev, "failed to initialize host\n");
519f122d33eSFelipe Balbi 			goto err2;
52072246da4SFelipe Balbi 		}
521d07e8819SFelipe Balbi 		break;
522a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
5233140e8cbSSebastian Andrzej Siewior 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
524d07e8819SFelipe Balbi 		ret = dwc3_host_init(dwc);
525d07e8819SFelipe Balbi 		if (ret) {
526802ca850SChanho Park 			dev_err(dev, "failed to initialize host\n");
527f122d33eSFelipe Balbi 			goto err2;
528d07e8819SFelipe Balbi 		}
529d07e8819SFelipe Balbi 
530d07e8819SFelipe Balbi 		ret = dwc3_gadget_init(dwc);
531d07e8819SFelipe Balbi 		if (ret) {
532802ca850SChanho Park 			dev_err(dev, "failed to initialize gadget\n");
533f122d33eSFelipe Balbi 			goto err2;
534d07e8819SFelipe Balbi 		}
535d07e8819SFelipe Balbi 		break;
5360949e99bSFelipe Balbi 	default:
537a45c82b8SRuchika Kharwar 		dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
538f122d33eSFelipe Balbi 		goto err2;
53972246da4SFelipe Balbi 	}
54072246da4SFelipe Balbi 
54172246da4SFelipe Balbi 	ret = dwc3_debugfs_init(dwc);
54272246da4SFelipe Balbi 	if (ret) {
543802ca850SChanho Park 		dev_err(dev, "failed to initialize debugfs\n");
544f122d33eSFelipe Balbi 		goto err3;
54572246da4SFelipe Balbi 	}
54672246da4SFelipe Balbi 
547802ca850SChanho Park 	pm_runtime_allow(dev);
54872246da4SFelipe Balbi 
54972246da4SFelipe Balbi 	return 0;
55072246da4SFelipe Balbi 
551f122d33eSFelipe Balbi err3:
552a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
553a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
55472246da4SFelipe Balbi 		dwc3_gadget_exit(dwc);
5550949e99bSFelipe Balbi 		break;
556a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
557d07e8819SFelipe Balbi 		dwc3_host_exit(dwc);
558d07e8819SFelipe Balbi 		break;
559a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
560d07e8819SFelipe Balbi 		dwc3_host_exit(dwc);
561d07e8819SFelipe Balbi 		dwc3_gadget_exit(dwc);
562d07e8819SFelipe Balbi 		break;
5630949e99bSFelipe Balbi 	default:
5640949e99bSFelipe Balbi 		/* do nothing */
5650949e99bSFelipe Balbi 		break;
5660949e99bSFelipe Balbi 	}
56772246da4SFelipe Balbi 
568f122d33eSFelipe Balbi err2:
569f122d33eSFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
570f122d33eSFelipe Balbi 
571802ca850SChanho Park err1:
57272246da4SFelipe Balbi 	dwc3_core_exit(dwc);
57372246da4SFelipe Balbi 
5743921426bSFelipe Balbi err0:
5753921426bSFelipe Balbi 	dwc3_free_event_buffers(dwc);
5763921426bSFelipe Balbi 
57772246da4SFelipe Balbi 	return ret;
57872246da4SFelipe Balbi }
57972246da4SFelipe Balbi 
580fb4e98abSBill Pemberton static int dwc3_remove(struct platform_device *pdev)
58172246da4SFelipe Balbi {
58272246da4SFelipe Balbi 	struct dwc3	*dwc = platform_get_drvdata(pdev);
58372246da4SFelipe Balbi 
5848ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 1);
5858ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 1);
5868ba007a9SKishon Vijay Abraham I 
58716b972a5SFelipe Balbi 	pm_runtime_put_sync(&pdev->dev);
58872246da4SFelipe Balbi 	pm_runtime_disable(&pdev->dev);
58972246da4SFelipe Balbi 
59072246da4SFelipe Balbi 	dwc3_debugfs_exit(dwc);
59172246da4SFelipe Balbi 
592a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
593a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
59472246da4SFelipe Balbi 		dwc3_gadget_exit(dwc);
5950949e99bSFelipe Balbi 		break;
596a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
597d07e8819SFelipe Balbi 		dwc3_host_exit(dwc);
598d07e8819SFelipe Balbi 		break;
599a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
600d07e8819SFelipe Balbi 		dwc3_host_exit(dwc);
601d07e8819SFelipe Balbi 		dwc3_gadget_exit(dwc);
602d07e8819SFelipe Balbi 		break;
6030949e99bSFelipe Balbi 	default:
6040949e99bSFelipe Balbi 		/* do nothing */
6050949e99bSFelipe Balbi 		break;
6060949e99bSFelipe Balbi 	}
60772246da4SFelipe Balbi 
608f122d33eSFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
609d9b4330aSFelipe Balbi 	dwc3_free_event_buffers(dwc);
61072246da4SFelipe Balbi 	dwc3_core_exit(dwc);
61172246da4SFelipe Balbi 
61272246da4SFelipe Balbi 	return 0;
61372246da4SFelipe Balbi }
61472246da4SFelipe Balbi 
61519fda7cdSJingoo Han #ifdef CONFIG_PM_SLEEP
6167415f17cSFelipe Balbi static int dwc3_prepare(struct device *dev)
6177415f17cSFelipe Balbi {
6187415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
6197415f17cSFelipe Balbi 	unsigned long	flags;
6207415f17cSFelipe Balbi 
6217415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
6227415f17cSFelipe Balbi 
623a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
624a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
625a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
6267415f17cSFelipe Balbi 		dwc3_gadget_prepare(dwc);
6277415f17cSFelipe Balbi 		/* FALLTHROUGH */
628a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
6297415f17cSFelipe Balbi 	default:
6307415f17cSFelipe Balbi 		dwc3_event_buffers_cleanup(dwc);
6317415f17cSFelipe Balbi 		break;
6327415f17cSFelipe Balbi 	}
6337415f17cSFelipe Balbi 
6347415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
6357415f17cSFelipe Balbi 
6367415f17cSFelipe Balbi 	return 0;
6377415f17cSFelipe Balbi }
6387415f17cSFelipe Balbi 
6397415f17cSFelipe Balbi static void dwc3_complete(struct device *dev)
6407415f17cSFelipe Balbi {
6417415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
6427415f17cSFelipe Balbi 	unsigned long	flags;
6437415f17cSFelipe Balbi 
6447415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
6457415f17cSFelipe Balbi 
646a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
647a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
648a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
6497415f17cSFelipe Balbi 		dwc3_gadget_complete(dwc);
6507415f17cSFelipe Balbi 		/* FALLTHROUGH */
651a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
6527415f17cSFelipe Balbi 	default:
6537415f17cSFelipe Balbi 		dwc3_event_buffers_setup(dwc);
6547415f17cSFelipe Balbi 		break;
6557415f17cSFelipe Balbi 	}
6567415f17cSFelipe Balbi 
6577415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
6587415f17cSFelipe Balbi }
6597415f17cSFelipe Balbi 
6607415f17cSFelipe Balbi static int dwc3_suspend(struct device *dev)
6617415f17cSFelipe Balbi {
6627415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
6637415f17cSFelipe Balbi 	unsigned long	flags;
6647415f17cSFelipe Balbi 
6657415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
6667415f17cSFelipe Balbi 
667a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
668a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
669a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
6707415f17cSFelipe Balbi 		dwc3_gadget_suspend(dwc);
6717415f17cSFelipe Balbi 		/* FALLTHROUGH */
672a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
6737415f17cSFelipe Balbi 	default:
6747415f17cSFelipe Balbi 		/* do nothing */
6757415f17cSFelipe Balbi 		break;
6767415f17cSFelipe Balbi 	}
6777415f17cSFelipe Balbi 
6787415f17cSFelipe Balbi 	dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL);
6797415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
6807415f17cSFelipe Balbi 
6817415f17cSFelipe Balbi 	usb_phy_shutdown(dwc->usb3_phy);
6827415f17cSFelipe Balbi 	usb_phy_shutdown(dwc->usb2_phy);
6837415f17cSFelipe Balbi 
6847415f17cSFelipe Balbi 	return 0;
6857415f17cSFelipe Balbi }
6867415f17cSFelipe Balbi 
6877415f17cSFelipe Balbi static int dwc3_resume(struct device *dev)
6887415f17cSFelipe Balbi {
6897415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
6907415f17cSFelipe Balbi 	unsigned long	flags;
6917415f17cSFelipe Balbi 
6927415f17cSFelipe Balbi 	usb_phy_init(dwc->usb3_phy);
6937415f17cSFelipe Balbi 	usb_phy_init(dwc->usb2_phy);
6947415f17cSFelipe Balbi 
6957415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
6967415f17cSFelipe Balbi 
6977415f17cSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
6987415f17cSFelipe Balbi 
699a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
700a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
701a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
7027415f17cSFelipe Balbi 		dwc3_gadget_resume(dwc);
7037415f17cSFelipe Balbi 		/* FALLTHROUGH */
704a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
7057415f17cSFelipe Balbi 	default:
7067415f17cSFelipe Balbi 		/* do nothing */
7077415f17cSFelipe Balbi 		break;
7087415f17cSFelipe Balbi 	}
7097415f17cSFelipe Balbi 
7107415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
7117415f17cSFelipe Balbi 
7127415f17cSFelipe Balbi 	pm_runtime_disable(dev);
7137415f17cSFelipe Balbi 	pm_runtime_set_active(dev);
7147415f17cSFelipe Balbi 	pm_runtime_enable(dev);
7157415f17cSFelipe Balbi 
7167415f17cSFelipe Balbi 	return 0;
7177415f17cSFelipe Balbi }
7187415f17cSFelipe Balbi 
7197415f17cSFelipe Balbi static const struct dev_pm_ops dwc3_dev_pm_ops = {
7207415f17cSFelipe Balbi 	.prepare	= dwc3_prepare,
7217415f17cSFelipe Balbi 	.complete	= dwc3_complete,
7227415f17cSFelipe Balbi 
7237415f17cSFelipe Balbi 	SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
7247415f17cSFelipe Balbi };
7257415f17cSFelipe Balbi 
7267415f17cSFelipe Balbi #define DWC3_PM_OPS	&(dwc3_dev_pm_ops)
7277415f17cSFelipe Balbi #else
7287415f17cSFelipe Balbi #define DWC3_PM_OPS	NULL
7297415f17cSFelipe Balbi #endif
7307415f17cSFelipe Balbi 
7315088b6f5SKishon Vijay Abraham I #ifdef CONFIG_OF
7325088b6f5SKishon Vijay Abraham I static const struct of_device_id of_dwc3_match[] = {
7335088b6f5SKishon Vijay Abraham I 	{
73422a5aa17SFelipe Balbi 		.compatible = "snps,dwc3"
73522a5aa17SFelipe Balbi 	},
73622a5aa17SFelipe Balbi 	{
7375088b6f5SKishon Vijay Abraham I 		.compatible = "synopsys,dwc3"
7385088b6f5SKishon Vijay Abraham I 	},
7395088b6f5SKishon Vijay Abraham I 	{ },
7405088b6f5SKishon Vijay Abraham I };
7415088b6f5SKishon Vijay Abraham I MODULE_DEVICE_TABLE(of, of_dwc3_match);
7425088b6f5SKishon Vijay Abraham I #endif
7435088b6f5SKishon Vijay Abraham I 
74472246da4SFelipe Balbi static struct platform_driver dwc3_driver = {
74572246da4SFelipe Balbi 	.probe		= dwc3_probe,
7467690417dSBill Pemberton 	.remove		= dwc3_remove,
74772246da4SFelipe Balbi 	.driver		= {
74872246da4SFelipe Balbi 		.name	= "dwc3",
7495088b6f5SKishon Vijay Abraham I 		.of_match_table	= of_match_ptr(of_dwc3_match),
7507415f17cSFelipe Balbi 		.pm	= DWC3_PM_OPS,
75172246da4SFelipe Balbi 	},
75272246da4SFelipe Balbi };
75372246da4SFelipe Balbi 
754b1116dccSTobias Klauser module_platform_driver(dwc3_driver);
755b1116dccSTobias Klauser 
7567ae4fc4dSSebastian Andrzej Siewior MODULE_ALIAS("platform:dwc3");
75772246da4SFelipe Balbi MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
7585945f789SFelipe Balbi MODULE_LICENSE("GPL v2");
75972246da4SFelipe Balbi MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
760