xref: /openbmc/linux/drivers/usb/dwc3/core.c (revision ddff14f1)
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  *
972246da4SFelipe Balbi  * Redistribution and use in source and binary forms, with or without
1072246da4SFelipe Balbi  * modification, are permitted provided that the following conditions
1172246da4SFelipe Balbi  * are met:
1272246da4SFelipe Balbi  * 1. Redistributions of source code must retain the above copyright
1372246da4SFelipe Balbi  *    notice, this list of conditions, and the following disclaimer,
1472246da4SFelipe Balbi  *    without modification.
1572246da4SFelipe Balbi  * 2. Redistributions in binary form must reproduce the above copyright
1672246da4SFelipe Balbi  *    notice, this list of conditions and the following disclaimer in the
1772246da4SFelipe Balbi  *    documentation and/or other materials provided with the distribution.
1872246da4SFelipe Balbi  * 3. The names of the above-listed copyright holders may not be used
1972246da4SFelipe Balbi  *    to endorse or promote products derived from this software without
2072246da4SFelipe Balbi  *    specific prior written permission.
2172246da4SFelipe Balbi  *
2272246da4SFelipe Balbi  * ALTERNATIVELY, this software may be distributed under the terms of the
2372246da4SFelipe Balbi  * GNU General Public License ("GPL") version 2, as published by the Free
2472246da4SFelipe Balbi  * Software Foundation.
2572246da4SFelipe Balbi  *
2672246da4SFelipe Balbi  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
2772246da4SFelipe Balbi  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
2872246da4SFelipe Balbi  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2972246da4SFelipe Balbi  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
3072246da4SFelipe Balbi  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
3172246da4SFelipe Balbi  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
3272246da4SFelipe Balbi  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
3372246da4SFelipe Balbi  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
3472246da4SFelipe Balbi  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3572246da4SFelipe Balbi  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3672246da4SFelipe Balbi  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3772246da4SFelipe Balbi  */
3872246da4SFelipe Balbi 
39a72e658bSFelipe Balbi #include <linux/module.h>
4072246da4SFelipe Balbi #include <linux/kernel.h>
4172246da4SFelipe Balbi #include <linux/slab.h>
4272246da4SFelipe Balbi #include <linux/spinlock.h>
4372246da4SFelipe Balbi #include <linux/platform_device.h>
4472246da4SFelipe Balbi #include <linux/pm_runtime.h>
4572246da4SFelipe Balbi #include <linux/interrupt.h>
4672246da4SFelipe Balbi #include <linux/ioport.h>
4772246da4SFelipe Balbi #include <linux/io.h>
4872246da4SFelipe Balbi #include <linux/list.h>
4972246da4SFelipe Balbi #include <linux/delay.h>
5072246da4SFelipe Balbi #include <linux/dma-mapping.h>
51457e84b6SFelipe Balbi #include <linux/of.h>
5272246da4SFelipe Balbi 
5351e1e7bcSFelipe Balbi #include <linux/usb/otg.h>
5472246da4SFelipe Balbi #include <linux/usb/ch9.h>
5572246da4SFelipe Balbi #include <linux/usb/gadget.h>
5672246da4SFelipe Balbi 
5772246da4SFelipe Balbi #include "core.h"
5872246da4SFelipe Balbi #include "gadget.h"
5972246da4SFelipe Balbi #include "io.h"
6072246da4SFelipe Balbi 
6172246da4SFelipe Balbi #include "debug.h"
6272246da4SFelipe Balbi 
636c167fc9SFelipe Balbi static char *maximum_speed = "super";
646c167fc9SFelipe Balbi module_param(maximum_speed, charp, 0);
656c167fc9SFelipe Balbi MODULE_PARM_DESC(maximum_speed, "Maximum supported speed.");
666c167fc9SFelipe Balbi 
678300dd23SFelipe Balbi /* -------------------------------------------------------------------------- */
688300dd23SFelipe Balbi 
693140e8cbSSebastian Andrzej Siewior void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
703140e8cbSSebastian Andrzej Siewior {
713140e8cbSSebastian Andrzej Siewior 	u32 reg;
723140e8cbSSebastian Andrzej Siewior 
733140e8cbSSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
743140e8cbSSebastian Andrzej Siewior 	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
753140e8cbSSebastian Andrzej Siewior 	reg |= DWC3_GCTL_PRTCAPDIR(mode);
763140e8cbSSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
773140e8cbSSebastian Andrzej Siewior }
788300dd23SFelipe Balbi 
7972246da4SFelipe Balbi /**
8072246da4SFelipe Balbi  * dwc3_core_soft_reset - Issues core soft reset and PHY reset
8172246da4SFelipe Balbi  * @dwc: pointer to our context structure
8272246da4SFelipe Balbi  */
8372246da4SFelipe Balbi static void dwc3_core_soft_reset(struct dwc3 *dwc)
8472246da4SFelipe Balbi {
8572246da4SFelipe Balbi 	u32		reg;
8672246da4SFelipe Balbi 
8772246da4SFelipe Balbi 	/* Before Resetting PHY, put Core in Reset */
8872246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
8972246da4SFelipe Balbi 	reg |= DWC3_GCTL_CORESOFTRESET;
9072246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
9172246da4SFelipe Balbi 
9272246da4SFelipe Balbi 	/* Assert USB3 PHY reset */
9372246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
9472246da4SFelipe Balbi 	reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
9572246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
9672246da4SFelipe Balbi 
9772246da4SFelipe Balbi 	/* Assert USB2 PHY reset */
9872246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
9972246da4SFelipe Balbi 	reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
10072246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
10172246da4SFelipe Balbi 
10251e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb2_phy);
10351e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb3_phy);
10472246da4SFelipe Balbi 	mdelay(100);
10572246da4SFelipe Balbi 
10672246da4SFelipe Balbi 	/* Clear USB3 PHY reset */
10772246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
10872246da4SFelipe Balbi 	reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
10972246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
11072246da4SFelipe Balbi 
11172246da4SFelipe Balbi 	/* Clear USB2 PHY reset */
11272246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
11372246da4SFelipe Balbi 	reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
11472246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
11572246da4SFelipe Balbi 
11645627ac6SPratyush Anand 	mdelay(100);
11745627ac6SPratyush Anand 
11872246da4SFelipe Balbi 	/* After PHYs are stable we can take Core out of reset state */
11972246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
12072246da4SFelipe Balbi 	reg &= ~DWC3_GCTL_CORESOFTRESET;
12172246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
12272246da4SFelipe Balbi }
12372246da4SFelipe Balbi 
12472246da4SFelipe Balbi /**
12572246da4SFelipe Balbi  * dwc3_free_one_event_buffer - Frees one event buffer
12672246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
12772246da4SFelipe Balbi  * @evt: Pointer to event buffer to be freed
12872246da4SFelipe Balbi  */
12972246da4SFelipe Balbi static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
13072246da4SFelipe Balbi 		struct dwc3_event_buffer *evt)
13172246da4SFelipe Balbi {
13272246da4SFelipe Balbi 	dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
13372246da4SFelipe Balbi }
13472246da4SFelipe Balbi 
13572246da4SFelipe Balbi /**
1361d046793SPaul Zimmerman  * dwc3_alloc_one_event_buffer - Allocates one event buffer structure
13772246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
13872246da4SFelipe Balbi  * @length: size of the event buffer
13972246da4SFelipe Balbi  *
1401d046793SPaul Zimmerman  * Returns a pointer to the allocated event buffer structure on success
14172246da4SFelipe Balbi  * otherwise ERR_PTR(errno).
14272246da4SFelipe Balbi  */
14367d0b500SFelipe Balbi static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
14467d0b500SFelipe Balbi 		unsigned length)
14572246da4SFelipe Balbi {
14672246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
14772246da4SFelipe Balbi 
148380f0d28SFelipe Balbi 	evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL);
14972246da4SFelipe Balbi 	if (!evt)
15072246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
15172246da4SFelipe Balbi 
15272246da4SFelipe Balbi 	evt->dwc	= dwc;
15372246da4SFelipe Balbi 	evt->length	= length;
15472246da4SFelipe Balbi 	evt->buf	= dma_alloc_coherent(dwc->dev, length,
15572246da4SFelipe Balbi 			&evt->dma, GFP_KERNEL);
156e32672f0SFelipe Balbi 	if (!evt->buf)
15772246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
15872246da4SFelipe Balbi 
15972246da4SFelipe Balbi 	return evt;
16072246da4SFelipe Balbi }
16172246da4SFelipe Balbi 
16272246da4SFelipe Balbi /**
16372246da4SFelipe Balbi  * dwc3_free_event_buffers - frees all allocated event buffers
16472246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
16572246da4SFelipe Balbi  */
16672246da4SFelipe Balbi static void dwc3_free_event_buffers(struct dwc3 *dwc)
16772246da4SFelipe Balbi {
16872246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
16972246da4SFelipe Balbi 	int i;
17072246da4SFelipe Balbi 
1719f622b2aSFelipe Balbi 	for (i = 0; i < dwc->num_event_buffers; i++) {
17272246da4SFelipe Balbi 		evt = dwc->ev_buffs[i];
17364b6c8a7SAnton Tikhomirov 		if (evt)
17472246da4SFelipe Balbi 			dwc3_free_one_event_buffer(dwc, evt);
17572246da4SFelipe Balbi 	}
17672246da4SFelipe Balbi }
17772246da4SFelipe Balbi 
17872246da4SFelipe Balbi /**
17972246da4SFelipe Balbi  * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
1801d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
18172246da4SFelipe Balbi  * @length: size of event buffer
18272246da4SFelipe Balbi  *
1831d046793SPaul Zimmerman  * Returns 0 on success otherwise negative errno. In the error case, dwc
18472246da4SFelipe Balbi  * may contain some buffers allocated but not all which were requested.
18572246da4SFelipe Balbi  */
18641ac7b3aSBill Pemberton static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
18772246da4SFelipe Balbi {
1889f622b2aSFelipe Balbi 	int			num;
18972246da4SFelipe Balbi 	int			i;
19072246da4SFelipe Balbi 
1919f622b2aSFelipe Balbi 	num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
1929f622b2aSFelipe Balbi 	dwc->num_event_buffers = num;
1939f622b2aSFelipe Balbi 
194380f0d28SFelipe Balbi 	dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num,
195380f0d28SFelipe Balbi 			GFP_KERNEL);
196457d3f21SFelipe Balbi 	if (!dwc->ev_buffs) {
197457d3f21SFelipe Balbi 		dev_err(dwc->dev, "can't allocate event buffers array\n");
198457d3f21SFelipe Balbi 		return -ENOMEM;
199457d3f21SFelipe Balbi 	}
200457d3f21SFelipe Balbi 
20172246da4SFelipe Balbi 	for (i = 0; i < num; i++) {
20272246da4SFelipe Balbi 		struct dwc3_event_buffer	*evt;
20372246da4SFelipe Balbi 
20472246da4SFelipe Balbi 		evt = dwc3_alloc_one_event_buffer(dwc, length);
20572246da4SFelipe Balbi 		if (IS_ERR(evt)) {
20672246da4SFelipe Balbi 			dev_err(dwc->dev, "can't allocate event buffer\n");
20772246da4SFelipe Balbi 			return PTR_ERR(evt);
20872246da4SFelipe Balbi 		}
20972246da4SFelipe Balbi 		dwc->ev_buffs[i] = evt;
21072246da4SFelipe Balbi 	}
21172246da4SFelipe Balbi 
21272246da4SFelipe Balbi 	return 0;
21372246da4SFelipe Balbi }
21472246da4SFelipe Balbi 
21572246da4SFelipe Balbi /**
21672246da4SFelipe Balbi  * dwc3_event_buffers_setup - setup our allocated event buffers
2171d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
21872246da4SFelipe Balbi  *
21972246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
22072246da4SFelipe Balbi  */
2217acd85e0SPaul Zimmerman static int dwc3_event_buffers_setup(struct dwc3 *dwc)
22272246da4SFelipe Balbi {
22372246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
22472246da4SFelipe Balbi 	int				n;
22572246da4SFelipe Balbi 
2269f622b2aSFelipe Balbi 	for (n = 0; n < dwc->num_event_buffers; n++) {
22772246da4SFelipe Balbi 		evt = dwc->ev_buffs[n];
22872246da4SFelipe Balbi 		dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
22972246da4SFelipe Balbi 				evt->buf, (unsigned long long) evt->dma,
23072246da4SFelipe Balbi 				evt->length);
23172246da4SFelipe Balbi 
2327acd85e0SPaul Zimmerman 		evt->lpos = 0;
2337acd85e0SPaul Zimmerman 
23472246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
23572246da4SFelipe Balbi 				lower_32_bits(evt->dma));
23672246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
23772246da4SFelipe Balbi 				upper_32_bits(evt->dma));
23872246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
23972246da4SFelipe Balbi 				evt->length & 0xffff);
24072246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
24172246da4SFelipe Balbi 	}
24272246da4SFelipe Balbi 
24372246da4SFelipe Balbi 	return 0;
24472246da4SFelipe Balbi }
24572246da4SFelipe Balbi 
24672246da4SFelipe Balbi static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
24772246da4SFelipe Balbi {
24872246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
24972246da4SFelipe Balbi 	int				n;
25072246da4SFelipe Balbi 
2519f622b2aSFelipe Balbi 	for (n = 0; n < dwc->num_event_buffers; n++) {
25272246da4SFelipe Balbi 		evt = dwc->ev_buffs[n];
2537acd85e0SPaul Zimmerman 
2547acd85e0SPaul Zimmerman 		evt->lpos = 0;
2557acd85e0SPaul Zimmerman 
25672246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
25772246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
25872246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
25972246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
26072246da4SFelipe Balbi 	}
26172246da4SFelipe Balbi }
26272246da4SFelipe Balbi 
263789451f6SFelipe Balbi static void dwc3_core_num_eps(struct dwc3 *dwc)
264789451f6SFelipe Balbi {
265789451f6SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
266789451f6SFelipe Balbi 
267789451f6SFelipe Balbi 	dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
268789451f6SFelipe Balbi 	dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
269789451f6SFelipe Balbi 
270789451f6SFelipe Balbi 	dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n",
271789451f6SFelipe Balbi 			dwc->num_in_eps, dwc->num_out_eps);
272789451f6SFelipe Balbi }
273789451f6SFelipe Balbi 
27441ac7b3aSBill Pemberton static void dwc3_cache_hwparams(struct dwc3 *dwc)
27526ceca97SFelipe Balbi {
27626ceca97SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
27726ceca97SFelipe Balbi 
27826ceca97SFelipe Balbi 	parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
27926ceca97SFelipe Balbi 	parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
28026ceca97SFelipe Balbi 	parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
28126ceca97SFelipe Balbi 	parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
28226ceca97SFelipe Balbi 	parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
28326ceca97SFelipe Balbi 	parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
28426ceca97SFelipe Balbi 	parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
28526ceca97SFelipe Balbi 	parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
28626ceca97SFelipe Balbi 	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
28726ceca97SFelipe Balbi }
28826ceca97SFelipe Balbi 
28972246da4SFelipe Balbi /**
29072246da4SFelipe Balbi  * dwc3_core_init - Low-level initialization of DWC3 Core
29172246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
29272246da4SFelipe Balbi  *
29372246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
29472246da4SFelipe Balbi  */
29541ac7b3aSBill Pemberton static int dwc3_core_init(struct dwc3 *dwc)
29672246da4SFelipe Balbi {
29772246da4SFelipe Balbi 	unsigned long		timeout;
29872246da4SFelipe Balbi 	u32			reg;
29972246da4SFelipe Balbi 	int			ret;
30072246da4SFelipe Balbi 
3017650bd74SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
3027650bd74SSebastian Andrzej Siewior 	/* This should read as U3 followed by revision number */
3037650bd74SSebastian Andrzej Siewior 	if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
3047650bd74SSebastian Andrzej Siewior 		dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
3057650bd74SSebastian Andrzej Siewior 		ret = -ENODEV;
3067650bd74SSebastian Andrzej Siewior 		goto err0;
3077650bd74SSebastian Andrzej Siewior 	}
308248b122bSFelipe Balbi 	dwc->revision = reg;
3097650bd74SSebastian Andrzej Siewior 
31072246da4SFelipe Balbi 	/* issue device SoftReset too */
31172246da4SFelipe Balbi 	timeout = jiffies + msecs_to_jiffies(500);
31272246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
31372246da4SFelipe Balbi 	do {
31472246da4SFelipe Balbi 		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
31572246da4SFelipe Balbi 		if (!(reg & DWC3_DCTL_CSFTRST))
31672246da4SFelipe Balbi 			break;
31772246da4SFelipe Balbi 
31872246da4SFelipe Balbi 		if (time_after(jiffies, timeout)) {
31972246da4SFelipe Balbi 			dev_err(dwc->dev, "Reset Timed Out\n");
32072246da4SFelipe Balbi 			ret = -ETIMEDOUT;
32172246da4SFelipe Balbi 			goto err0;
32272246da4SFelipe Balbi 		}
32372246da4SFelipe Balbi 
32472246da4SFelipe Balbi 		cpu_relax();
32572246da4SFelipe Balbi 	} while (true);
32672246da4SFelipe Balbi 
32758a0f23fSPratyush Anand 	dwc3_core_soft_reset(dwc);
32858a0f23fSPratyush Anand 
3294878a028SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
3303e87c42aSPaul Zimmerman 	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
3314878a028SSebastian Andrzej Siewior 	reg &= ~DWC3_GCTL_DISSCRAMBLE;
3324878a028SSebastian Andrzej Siewior 
333164d7731SSebastian Andrzej Siewior 	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
3344878a028SSebastian Andrzej Siewior 	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
3354878a028SSebastian Andrzej Siewior 		reg &= ~DWC3_GCTL_DSBLCLKGTNG;
3364878a028SSebastian Andrzej Siewior 		break;
3374878a028SSebastian Andrzej Siewior 	default:
3384878a028SSebastian Andrzej Siewior 		dev_dbg(dwc->dev, "No power optimization available\n");
3394878a028SSebastian Andrzej Siewior 	}
3404878a028SSebastian Andrzej Siewior 
3414878a028SSebastian Andrzej Siewior 	/*
3424878a028SSebastian Andrzej Siewior 	 * WORKAROUND: DWC3 revisions <1.90a have a bug
3431d046793SPaul Zimmerman 	 * where the device can fail to connect at SuperSpeed
3444878a028SSebastian Andrzej Siewior 	 * and falls back to high-speed mode which causes
3451d046793SPaul Zimmerman 	 * the device to enter a Connect/Disconnect loop
3464878a028SSebastian Andrzej Siewior 	 */
3474878a028SSebastian Andrzej Siewior 	if (dwc->revision < DWC3_REVISION_190A)
3484878a028SSebastian Andrzej Siewior 		reg |= DWC3_GCTL_U2RSTECN;
3494878a028SSebastian Andrzej Siewior 
350789451f6SFelipe Balbi 	dwc3_core_num_eps(dwc);
351789451f6SFelipe Balbi 
3524878a028SSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
3534878a028SSebastian Andrzej Siewior 
35472246da4SFelipe Balbi 	return 0;
35572246da4SFelipe Balbi 
35672246da4SFelipe Balbi err0:
35772246da4SFelipe Balbi 	return ret;
35872246da4SFelipe Balbi }
35972246da4SFelipe Balbi 
36072246da4SFelipe Balbi static void dwc3_core_exit(struct dwc3 *dwc)
36172246da4SFelipe Balbi {
36201b8daf7SVivek Gautam 	usb_phy_shutdown(dwc->usb2_phy);
36301b8daf7SVivek Gautam 	usb_phy_shutdown(dwc->usb3_phy);
36472246da4SFelipe Balbi }
36572246da4SFelipe Balbi 
36672246da4SFelipe Balbi #define DWC3_ALIGN_MASK		(16 - 1)
36772246da4SFelipe Balbi 
36841ac7b3aSBill Pemberton static int dwc3_probe(struct platform_device *pdev)
36972246da4SFelipe Balbi {
370457e84b6SFelipe Balbi 	struct device_node	*node = pdev->dev.of_node;
37172246da4SFelipe Balbi 	struct resource		*res;
37272246da4SFelipe Balbi 	struct dwc3		*dwc;
373802ca850SChanho Park 	struct device		*dev = &pdev->dev;
3740949e99bSFelipe Balbi 
37572246da4SFelipe Balbi 	int			ret = -ENOMEM;
3760949e99bSFelipe Balbi 
3770949e99bSFelipe Balbi 	void __iomem		*regs;
37872246da4SFelipe Balbi 	void			*mem;
37972246da4SFelipe Balbi 
3800949e99bSFelipe Balbi 	u8			mode;
3810949e99bSFelipe Balbi 
382802ca850SChanho Park 	mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
38372246da4SFelipe Balbi 	if (!mem) {
384802ca850SChanho Park 		dev_err(dev, "not enough memory\n");
385802ca850SChanho Park 		return -ENOMEM;
38672246da4SFelipe Balbi 	}
38772246da4SFelipe Balbi 	dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
38872246da4SFelipe Balbi 	dwc->mem = mem;
38972246da4SFelipe Balbi 
39051249dcaSIdo Shayevitz 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
39172246da4SFelipe Balbi 	if (!res) {
39251249dcaSIdo Shayevitz 		dev_err(dev, "missing IRQ\n");
393802ca850SChanho Park 		return -ENODEV;
39472246da4SFelipe Balbi 	}
395066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[1].start = res->start;
396066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[1].end = res->end;
397066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[1].flags = res->flags;
398066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[1].name = res->name;
39972246da4SFelipe Balbi 
40051249dcaSIdo Shayevitz 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
40151249dcaSIdo Shayevitz 	if (!res) {
40251249dcaSIdo Shayevitz 		dev_err(dev, "missing memory resource\n");
40351249dcaSIdo Shayevitz 		return -ENODEV;
40451249dcaSIdo Shayevitz 	}
405066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[0].start = res->start;
40651249dcaSIdo Shayevitz 	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
40751249dcaSIdo Shayevitz 					DWC3_XHCI_REGS_END;
408066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[0].flags = res->flags;
409066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[0].name = res->name;
410d07e8819SFelipe Balbi 
41151249dcaSIdo Shayevitz 	 /*
41251249dcaSIdo Shayevitz 	  * Request memory region but exclude xHCI regs,
41351249dcaSIdo Shayevitz 	  * since it will be requested by the xhci-plat driver.
41451249dcaSIdo Shayevitz 	  */
41551249dcaSIdo Shayevitz 	res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START,
41651249dcaSIdo Shayevitz 			resource_size(res) - DWC3_GLOBALS_REGS_START,
417802ca850SChanho Park 			dev_name(dev));
41872246da4SFelipe Balbi 	if (!res) {
419802ca850SChanho Park 		dev_err(dev, "can't request mem region\n");
420802ca850SChanho Park 		return -ENOMEM;
42172246da4SFelipe Balbi 	}
42272246da4SFelipe Balbi 
423b7e38aa6SFelipe Balbi 	regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
42472246da4SFelipe Balbi 	if (!regs) {
425802ca850SChanho Park 		dev_err(dev, "ioremap failed\n");
426802ca850SChanho Park 		return -ENOMEM;
42772246da4SFelipe Balbi 	}
42872246da4SFelipe Balbi 
4295088b6f5SKishon Vijay Abraham I 	if (node) {
4305088b6f5SKishon Vijay Abraham I 		dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
4315088b6f5SKishon Vijay Abraham I 		dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
4325088b6f5SKishon Vijay Abraham I 	} else {
43351e1e7bcSFelipe Balbi 		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
4345088b6f5SKishon Vijay Abraham I 		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
4355088b6f5SKishon Vijay Abraham I 	}
4365088b6f5SKishon Vijay Abraham I 
43751e1e7bcSFelipe Balbi 	if (IS_ERR_OR_NULL(dwc->usb2_phy)) {
43851e1e7bcSFelipe Balbi 		dev_err(dev, "no usb2 phy configured\n");
43951e1e7bcSFelipe Balbi 		return -EPROBE_DEFER;
44051e1e7bcSFelipe Balbi 	}
44151e1e7bcSFelipe Balbi 
44251e1e7bcSFelipe Balbi 	if (IS_ERR_OR_NULL(dwc->usb3_phy)) {
44351e1e7bcSFelipe Balbi 		dev_err(dev, "no usb3 phy configured\n");
44451e1e7bcSFelipe Balbi 		return -EPROBE_DEFER;
44551e1e7bcSFelipe Balbi 	}
44651e1e7bcSFelipe Balbi 
4478ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 0);
4488ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 0);
4498ba007a9SKishon Vijay Abraham I 
45072246da4SFelipe Balbi 	spin_lock_init(&dwc->lock);
45172246da4SFelipe Balbi 	platform_set_drvdata(pdev, dwc);
45272246da4SFelipe Balbi 
45372246da4SFelipe Balbi 	dwc->regs	= regs;
45472246da4SFelipe Balbi 	dwc->regs_size	= resource_size(res);
455802ca850SChanho Park 	dwc->dev	= dev;
45672246da4SFelipe Balbi 
457ddff14f1SKishon Vijay Abraham I 	dev->dma_mask	= dev->parent->dma_mask;
458ddff14f1SKishon Vijay Abraham I 	dev->dma_parms	= dev->parent->dma_parms;
459ddff14f1SKishon Vijay Abraham I 	dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
460ddff14f1SKishon Vijay Abraham I 
4616c167fc9SFelipe Balbi 	if (!strncmp("super", maximum_speed, 5))
4626c167fc9SFelipe Balbi 		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
4636c167fc9SFelipe Balbi 	else if (!strncmp("high", maximum_speed, 4))
4646c167fc9SFelipe Balbi 		dwc->maximum_speed = DWC3_DCFG_HIGHSPEED;
4656c167fc9SFelipe Balbi 	else if (!strncmp("full", maximum_speed, 4))
4666c167fc9SFelipe Balbi 		dwc->maximum_speed = DWC3_DCFG_FULLSPEED1;
4676c167fc9SFelipe Balbi 	else if (!strncmp("low", maximum_speed, 3))
4686c167fc9SFelipe Balbi 		dwc->maximum_speed = DWC3_DCFG_LOWSPEED;
4696c167fc9SFelipe Balbi 	else
4706c167fc9SFelipe Balbi 		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
4716c167fc9SFelipe Balbi 
4725088b6f5SKishon Vijay Abraham I 	dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
473457e84b6SFelipe Balbi 
474802ca850SChanho Park 	pm_runtime_enable(dev);
475802ca850SChanho Park 	pm_runtime_get_sync(dev);
476802ca850SChanho Park 	pm_runtime_forbid(dev);
47772246da4SFelipe Balbi 
4784fd24483SKishon Vijay Abraham I 	dwc3_cache_hwparams(dwc);
4794fd24483SKishon Vijay Abraham I 
4803921426bSFelipe Balbi 	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
4813921426bSFelipe Balbi 	if (ret) {
4823921426bSFelipe Balbi 		dev_err(dwc->dev, "failed to allocate event buffers\n");
4833921426bSFelipe Balbi 		ret = -ENOMEM;
4843921426bSFelipe Balbi 		goto err0;
4853921426bSFelipe Balbi 	}
4863921426bSFelipe Balbi 
48772246da4SFelipe Balbi 	ret = dwc3_core_init(dwc);
48872246da4SFelipe Balbi 	if (ret) {
489802ca850SChanho Park 		dev_err(dev, "failed to initialize core\n");
4903921426bSFelipe Balbi 		goto err0;
49172246da4SFelipe Balbi 	}
49272246da4SFelipe Balbi 
493f122d33eSFelipe Balbi 	ret = dwc3_event_buffers_setup(dwc);
494f122d33eSFelipe Balbi 	if (ret) {
495f122d33eSFelipe Balbi 		dev_err(dwc->dev, "failed to setup event buffers\n");
496f122d33eSFelipe Balbi 		goto err1;
497f122d33eSFelipe Balbi 	}
498f122d33eSFelipe Balbi 
499cd051da2SVivek Gautam 	if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
500cd051da2SVivek Gautam 		mode = DWC3_MODE_HOST;
501cd051da2SVivek Gautam 	else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
502cd051da2SVivek Gautam 		mode = DWC3_MODE_DEVICE;
503cd051da2SVivek Gautam 	else
504cd051da2SVivek Gautam 		mode = DWC3_MODE_DRD;
5050949e99bSFelipe Balbi 
5060949e99bSFelipe Balbi 	switch (mode) {
5070949e99bSFelipe Balbi 	case DWC3_MODE_DEVICE:
5083140e8cbSSebastian Andrzej Siewior 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
50972246da4SFelipe Balbi 		ret = dwc3_gadget_init(dwc);
51072246da4SFelipe Balbi 		if (ret) {
511802ca850SChanho Park 			dev_err(dev, "failed to initialize gadget\n");
512f122d33eSFelipe Balbi 			goto err2;
51372246da4SFelipe Balbi 		}
5140949e99bSFelipe Balbi 		break;
515d07e8819SFelipe Balbi 	case DWC3_MODE_HOST:
5163140e8cbSSebastian Andrzej Siewior 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
517d07e8819SFelipe Balbi 		ret = dwc3_host_init(dwc);
518d07e8819SFelipe Balbi 		if (ret) {
519802ca850SChanho Park 			dev_err(dev, "failed to initialize host\n");
520f122d33eSFelipe Balbi 			goto err2;
52172246da4SFelipe Balbi 		}
522d07e8819SFelipe Balbi 		break;
523d07e8819SFelipe Balbi 	case DWC3_MODE_DRD:
5243140e8cbSSebastian Andrzej Siewior 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
525d07e8819SFelipe Balbi 		ret = dwc3_host_init(dwc);
526d07e8819SFelipe Balbi 		if (ret) {
527802ca850SChanho Park 			dev_err(dev, "failed to initialize host\n");
528f122d33eSFelipe Balbi 			goto err2;
529d07e8819SFelipe Balbi 		}
530d07e8819SFelipe Balbi 
531d07e8819SFelipe Balbi 		ret = dwc3_gadget_init(dwc);
532d07e8819SFelipe Balbi 		if (ret) {
533802ca850SChanho Park 			dev_err(dev, "failed to initialize gadget\n");
534f122d33eSFelipe Balbi 			goto err2;
535d07e8819SFelipe Balbi 		}
536d07e8819SFelipe Balbi 		break;
5370949e99bSFelipe Balbi 	default:
538802ca850SChanho Park 		dev_err(dev, "Unsupported mode of operation %d\n", mode);
539f122d33eSFelipe Balbi 		goto err2;
54072246da4SFelipe Balbi 	}
5410949e99bSFelipe Balbi 	dwc->mode = mode;
54272246da4SFelipe Balbi 
54372246da4SFelipe Balbi 	ret = dwc3_debugfs_init(dwc);
54472246da4SFelipe Balbi 	if (ret) {
545802ca850SChanho Park 		dev_err(dev, "failed to initialize debugfs\n");
546f122d33eSFelipe Balbi 		goto err3;
54772246da4SFelipe Balbi 	}
54872246da4SFelipe Balbi 
549802ca850SChanho Park 	pm_runtime_allow(dev);
55072246da4SFelipe Balbi 
55172246da4SFelipe Balbi 	return 0;
55272246da4SFelipe Balbi 
553f122d33eSFelipe Balbi err3:
5540949e99bSFelipe Balbi 	switch (mode) {
5550949e99bSFelipe Balbi 	case DWC3_MODE_DEVICE:
55672246da4SFelipe Balbi 		dwc3_gadget_exit(dwc);
5570949e99bSFelipe Balbi 		break;
558d07e8819SFelipe Balbi 	case DWC3_MODE_HOST:
559d07e8819SFelipe Balbi 		dwc3_host_exit(dwc);
560d07e8819SFelipe Balbi 		break;
561d07e8819SFelipe Balbi 	case DWC3_MODE_DRD:
562d07e8819SFelipe Balbi 		dwc3_host_exit(dwc);
563d07e8819SFelipe Balbi 		dwc3_gadget_exit(dwc);
564d07e8819SFelipe Balbi 		break;
5650949e99bSFelipe Balbi 	default:
5660949e99bSFelipe Balbi 		/* do nothing */
5670949e99bSFelipe Balbi 		break;
5680949e99bSFelipe Balbi 	}
56972246da4SFelipe Balbi 
570f122d33eSFelipe Balbi err2:
571f122d33eSFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
572f122d33eSFelipe Balbi 
573802ca850SChanho Park err1:
57472246da4SFelipe Balbi 	dwc3_core_exit(dwc);
57572246da4SFelipe Balbi 
5763921426bSFelipe Balbi err0:
5773921426bSFelipe Balbi 	dwc3_free_event_buffers(dwc);
5783921426bSFelipe Balbi 
57972246da4SFelipe Balbi 	return ret;
58072246da4SFelipe Balbi }
58172246da4SFelipe Balbi 
582fb4e98abSBill Pemberton static int dwc3_remove(struct platform_device *pdev)
58372246da4SFelipe Balbi {
58472246da4SFelipe Balbi 	struct dwc3	*dwc = platform_get_drvdata(pdev);
58572246da4SFelipe Balbi 
5868ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 1);
5878ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 1);
5888ba007a9SKishon Vijay Abraham I 
58972246da4SFelipe Balbi 	pm_runtime_put(&pdev->dev);
59072246da4SFelipe Balbi 	pm_runtime_disable(&pdev->dev);
59172246da4SFelipe Balbi 
59272246da4SFelipe Balbi 	dwc3_debugfs_exit(dwc);
59372246da4SFelipe Balbi 
5940949e99bSFelipe Balbi 	switch (dwc->mode) {
5950949e99bSFelipe Balbi 	case DWC3_MODE_DEVICE:
59672246da4SFelipe Balbi 		dwc3_gadget_exit(dwc);
5970949e99bSFelipe Balbi 		break;
598d07e8819SFelipe Balbi 	case DWC3_MODE_HOST:
599d07e8819SFelipe Balbi 		dwc3_host_exit(dwc);
600d07e8819SFelipe Balbi 		break;
601d07e8819SFelipe Balbi 	case DWC3_MODE_DRD:
602d07e8819SFelipe Balbi 		dwc3_host_exit(dwc);
603d07e8819SFelipe Balbi 		dwc3_gadget_exit(dwc);
604d07e8819SFelipe Balbi 		break;
6050949e99bSFelipe Balbi 	default:
6060949e99bSFelipe Balbi 		/* do nothing */
6070949e99bSFelipe Balbi 		break;
6080949e99bSFelipe Balbi 	}
60972246da4SFelipe Balbi 
610f122d33eSFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
611d9b4330aSFelipe Balbi 	dwc3_free_event_buffers(dwc);
61272246da4SFelipe Balbi 	dwc3_core_exit(dwc);
61372246da4SFelipe Balbi 
61472246da4SFelipe Balbi 	return 0;
61572246da4SFelipe Balbi }
61672246da4SFelipe Balbi 
6177415f17cSFelipe Balbi #ifdef CONFIG_PM
6187415f17cSFelipe Balbi static int dwc3_prepare(struct device *dev)
6197415f17cSFelipe Balbi {
6207415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
6217415f17cSFelipe Balbi 	unsigned long	flags;
6227415f17cSFelipe Balbi 
6237415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
6247415f17cSFelipe Balbi 
6257415f17cSFelipe Balbi 	switch (dwc->mode) {
6267415f17cSFelipe Balbi 	case DWC3_MODE_DEVICE:
6277415f17cSFelipe Balbi 	case DWC3_MODE_DRD:
6287415f17cSFelipe Balbi 		dwc3_gadget_prepare(dwc);
6297415f17cSFelipe Balbi 		/* FALLTHROUGH */
6307415f17cSFelipe Balbi 	case DWC3_MODE_HOST:
6317415f17cSFelipe Balbi 	default:
6327415f17cSFelipe Balbi 		dwc3_event_buffers_cleanup(dwc);
6337415f17cSFelipe Balbi 		break;
6347415f17cSFelipe Balbi 	}
6357415f17cSFelipe Balbi 
6367415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
6377415f17cSFelipe Balbi 
6387415f17cSFelipe Balbi 	return 0;
6397415f17cSFelipe Balbi }
6407415f17cSFelipe Balbi 
6417415f17cSFelipe Balbi static void dwc3_complete(struct device *dev)
6427415f17cSFelipe Balbi {
6437415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
6447415f17cSFelipe Balbi 	unsigned long	flags;
6457415f17cSFelipe Balbi 
6467415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
6477415f17cSFelipe Balbi 
6487415f17cSFelipe Balbi 	switch (dwc->mode) {
6497415f17cSFelipe Balbi 	case DWC3_MODE_DEVICE:
6507415f17cSFelipe Balbi 	case DWC3_MODE_DRD:
6517415f17cSFelipe Balbi 		dwc3_gadget_complete(dwc);
6527415f17cSFelipe Balbi 		/* FALLTHROUGH */
6537415f17cSFelipe Balbi 	case DWC3_MODE_HOST:
6547415f17cSFelipe Balbi 	default:
6557415f17cSFelipe Balbi 		dwc3_event_buffers_setup(dwc);
6567415f17cSFelipe Balbi 		break;
6577415f17cSFelipe Balbi 	}
6587415f17cSFelipe Balbi 
6597415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
6607415f17cSFelipe Balbi }
6617415f17cSFelipe Balbi 
6627415f17cSFelipe Balbi static int dwc3_suspend(struct device *dev)
6637415f17cSFelipe Balbi {
6647415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
6657415f17cSFelipe Balbi 	unsigned long	flags;
6667415f17cSFelipe Balbi 
6677415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
6687415f17cSFelipe Balbi 
6697415f17cSFelipe Balbi 	switch (dwc->mode) {
6707415f17cSFelipe Balbi 	case DWC3_MODE_DEVICE:
6717415f17cSFelipe Balbi 	case DWC3_MODE_DRD:
6727415f17cSFelipe Balbi 		dwc3_gadget_suspend(dwc);
6737415f17cSFelipe Balbi 		/* FALLTHROUGH */
6747415f17cSFelipe Balbi 	case DWC3_MODE_HOST:
6757415f17cSFelipe Balbi 	default:
6767415f17cSFelipe Balbi 		/* do nothing */
6777415f17cSFelipe Balbi 		break;
6787415f17cSFelipe Balbi 	}
6797415f17cSFelipe Balbi 
6807415f17cSFelipe Balbi 	dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL);
6817415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
6827415f17cSFelipe Balbi 
6837415f17cSFelipe Balbi 	usb_phy_shutdown(dwc->usb3_phy);
6847415f17cSFelipe Balbi 	usb_phy_shutdown(dwc->usb2_phy);
6857415f17cSFelipe Balbi 
6867415f17cSFelipe Balbi 	return 0;
6877415f17cSFelipe Balbi }
6887415f17cSFelipe Balbi 
6897415f17cSFelipe Balbi static int dwc3_resume(struct device *dev)
6907415f17cSFelipe Balbi {
6917415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
6927415f17cSFelipe Balbi 	unsigned long	flags;
6937415f17cSFelipe Balbi 
6947415f17cSFelipe Balbi 	usb_phy_init(dwc->usb3_phy);
6957415f17cSFelipe Balbi 	usb_phy_init(dwc->usb2_phy);
6967415f17cSFelipe Balbi 	msleep(100);
6977415f17cSFelipe Balbi 
6987415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
6997415f17cSFelipe Balbi 
7007415f17cSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
7017415f17cSFelipe Balbi 
7027415f17cSFelipe Balbi 	switch (dwc->mode) {
7037415f17cSFelipe Balbi 	case DWC3_MODE_DEVICE:
7047415f17cSFelipe Balbi 	case DWC3_MODE_DRD:
7057415f17cSFelipe Balbi 		dwc3_gadget_resume(dwc);
7067415f17cSFelipe Balbi 		/* FALLTHROUGH */
7077415f17cSFelipe Balbi 	case DWC3_MODE_HOST:
7087415f17cSFelipe Balbi 	default:
7097415f17cSFelipe Balbi 		/* do nothing */
7107415f17cSFelipe Balbi 		break;
7117415f17cSFelipe Balbi 	}
7127415f17cSFelipe Balbi 
7137415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
7147415f17cSFelipe Balbi 
7157415f17cSFelipe Balbi 	pm_runtime_disable(dev);
7167415f17cSFelipe Balbi 	pm_runtime_set_active(dev);
7177415f17cSFelipe Balbi 	pm_runtime_enable(dev);
7187415f17cSFelipe Balbi 
7197415f17cSFelipe Balbi 	return 0;
7207415f17cSFelipe Balbi }
7217415f17cSFelipe Balbi 
7227415f17cSFelipe Balbi static const struct dev_pm_ops dwc3_dev_pm_ops = {
7237415f17cSFelipe Balbi 	.prepare	= dwc3_prepare,
7247415f17cSFelipe Balbi 	.complete	= dwc3_complete,
7257415f17cSFelipe Balbi 
7267415f17cSFelipe Balbi 	SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
7277415f17cSFelipe Balbi };
7287415f17cSFelipe Balbi 
7297415f17cSFelipe Balbi #define DWC3_PM_OPS	&(dwc3_dev_pm_ops)
7307415f17cSFelipe Balbi #else
7317415f17cSFelipe Balbi #define DWC3_PM_OPS	NULL
7327415f17cSFelipe Balbi #endif
7337415f17cSFelipe Balbi 
7345088b6f5SKishon Vijay Abraham I #ifdef CONFIG_OF
7355088b6f5SKishon Vijay Abraham I static const struct of_device_id of_dwc3_match[] = {
7365088b6f5SKishon Vijay Abraham I 	{
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>");
75872246da4SFelipe Balbi MODULE_LICENSE("Dual BSD/GPL");
75972246da4SFelipe Balbi MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
760