core.c 15.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
/**
 * core.c - DesignWare USB3 DRD Controller Core file
 *
 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
 *
 * Authors: Felipe Balbi <balbi@ti.com>,
 *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer,
 *    without modification.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The names of the above-listed copyright holders may not be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * ALTERNATIVELY, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2, as published by the Free
 * Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

39
#include <linux/module.h>
40 41 42 43 44 45 46 47 48 49 50
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/list.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
51
#include <linux/of.h>
52

F
Felipe Balbi 已提交
53
#include <linux/usb/otg.h>
54 55 56 57 58 59 60 61 62
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>

#include "core.h"
#include "gadget.h"
#include "io.h"

#include "debug.h"

63 64 65 66
static char *maximum_speed = "super";
module_param(maximum_speed, charp, 0);
MODULE_PARM_DESC(maximum_speed, "Maximum supported speed.");

67 68
/* -------------------------------------------------------------------------- */

69 70 71 72 73 74 75 76 77
void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
{
	u32 reg;

	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
	reg |= DWC3_GCTL_PRTCAPDIR(mode);
	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
}
78

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
/**
 * dwc3_core_soft_reset - Issues core soft reset and PHY reset
 * @dwc: pointer to our context structure
 */
static void dwc3_core_soft_reset(struct dwc3 *dwc)
{
	u32		reg;

	/* Before Resetting PHY, put Core in Reset */
	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
	reg |= DWC3_GCTL_CORESOFTRESET;
	dwc3_writel(dwc->regs, DWC3_GCTL, reg);

	/* Assert USB3 PHY reset */
	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
	reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);

	/* Assert USB2 PHY reset */
	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
	reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);

F
Felipe Balbi 已提交
102 103
	usb_phy_init(dwc->usb2_phy);
	usb_phy_init(dwc->usb3_phy);
104 105 106 107 108 109 110 111 112 113 114 115
	mdelay(100);

	/* Clear USB3 PHY reset */
	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
	reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);

	/* Clear USB2 PHY reset */
	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
	reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);

116 117
	mdelay(100);

118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
	/* After PHYs are stable we can take Core out of reset state */
	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
	reg &= ~DWC3_GCTL_CORESOFTRESET;
	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
}

/**
 * dwc3_free_one_event_buffer - Frees one event buffer
 * @dwc: Pointer to our controller context structure
 * @evt: Pointer to event buffer to be freed
 */
static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
		struct dwc3_event_buffer *evt)
{
	dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
}

/**
136
 * dwc3_alloc_one_event_buffer - Allocates one event buffer structure
137 138 139
 * @dwc: Pointer to our controller context structure
 * @length: size of the event buffer
 *
140
 * Returns a pointer to the allocated event buffer structure on success
141 142 143 144 145 146 147
 * otherwise ERR_PTR(errno).
 */
static struct dwc3_event_buffer *__devinit
dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length)
{
	struct dwc3_event_buffer	*evt;

148
	evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL);
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
	if (!evt)
		return ERR_PTR(-ENOMEM);

	evt->dwc	= dwc;
	evt->length	= length;
	evt->buf	= dma_alloc_coherent(dwc->dev, length,
			&evt->dma, GFP_KERNEL);
	if (!evt->buf) {
		kfree(evt);
		return ERR_PTR(-ENOMEM);
	}

	return evt;
}

/**
 * dwc3_free_event_buffers - frees all allocated event buffers
 * @dwc: Pointer to our controller context structure
 */
static void dwc3_free_event_buffers(struct dwc3 *dwc)
{
	struct dwc3_event_buffer	*evt;
	int i;

173
	for (i = 0; i < dwc->num_event_buffers; i++) {
174
		evt = dwc->ev_buffs[i];
175
		if (evt)
176 177 178 179 180 181
			dwc3_free_one_event_buffer(dwc, evt);
	}
}

/**
 * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
182
 * @dwc: pointer to our controller context structure
183 184
 * @length: size of event buffer
 *
185
 * Returns 0 on success otherwise negative errno. In the error case, dwc
186 187
 * may contain some buffers allocated but not all which were requested.
 */
188
static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
189
{
190
	int			num;
191 192
	int			i;

193 194 195
	num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
	dwc->num_event_buffers = num;

196 197
	dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num,
			GFP_KERNEL);
198 199 200 201 202
	if (!dwc->ev_buffs) {
		dev_err(dwc->dev, "can't allocate event buffers array\n");
		return -ENOMEM;
	}

203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
	for (i = 0; i < num; i++) {
		struct dwc3_event_buffer	*evt;

		evt = dwc3_alloc_one_event_buffer(dwc, length);
		if (IS_ERR(evt)) {
			dev_err(dwc->dev, "can't allocate event buffer\n");
			return PTR_ERR(evt);
		}
		dwc->ev_buffs[i] = evt;
	}

	return 0;
}

/**
 * dwc3_event_buffers_setup - setup our allocated event buffers
219
 * @dwc: pointer to our controller context structure
220 221 222
 *
 * Returns 0 on success otherwise negative errno.
 */
223
static int dwc3_event_buffers_setup(struct dwc3 *dwc)
224 225 226 227
{
	struct dwc3_event_buffer	*evt;
	int				n;

228
	for (n = 0; n < dwc->num_event_buffers; n++) {
229 230 231 232 233
		evt = dwc->ev_buffs[n];
		dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
				evt->buf, (unsigned long long) evt->dma,
				evt->length);

234 235
		evt->lpos = 0;

236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
				lower_32_bits(evt->dma));
		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
				upper_32_bits(evt->dma));
		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
				evt->length & 0xffff);
		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
	}

	return 0;
}

static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
{
	struct dwc3_event_buffer	*evt;
	int				n;

253
	for (n = 0; n < dwc->num_event_buffers; n++) {
254
		evt = dwc->ev_buffs[n];
255 256 257

		evt->lpos = 0;

258 259 260 261 262 263 264
		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
	}
}

265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
static void __devinit dwc3_cache_hwparams(struct dwc3 *dwc)
{
	struct dwc3_hwparams	*parms = &dwc->hwparams;

	parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
	parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
	parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
	parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
	parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
	parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
	parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
	parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
}

280 281 282 283 284 285 286 287 288 289 290 291
/**
 * dwc3_core_init - Low-level initialization of DWC3 Core
 * @dwc: Pointer to our controller context structure
 *
 * Returns 0 on success otherwise negative errno.
 */
static int __devinit dwc3_core_init(struct dwc3 *dwc)
{
	unsigned long		timeout;
	u32			reg;
	int			ret;

292 293 294 295 296 297 298
	reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
	/* This should read as U3 followed by revision number */
	if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
		dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
		ret = -ENODEV;
		goto err0;
	}
299
	dwc->revision = reg;
300

301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
	/* issue device SoftReset too */
	timeout = jiffies + msecs_to_jiffies(500);
	dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
	do {
		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
		if (!(reg & DWC3_DCTL_CSFTRST))
			break;

		if (time_after(jiffies, timeout)) {
			dev_err(dwc->dev, "Reset Timed Out\n");
			ret = -ETIMEDOUT;
			goto err0;
		}

		cpu_relax();
	} while (true);

318 319
	dwc3_core_soft_reset(dwc);

320 321
	dwc3_cache_hwparams(dwc);

322
	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
323
	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
324 325
	reg &= ~DWC3_GCTL_DISSCRAMBLE;

326
	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
327 328 329 330 331 332 333 334 335
	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
		reg &= ~DWC3_GCTL_DSBLCLKGTNG;
		break;
	default:
		dev_dbg(dwc->dev, "No power optimization available\n");
	}

	/*
	 * WORKAROUND: DWC3 revisions <1.90a have a bug
336
	 * where the device can fail to connect at SuperSpeed
337
	 * and falls back to high-speed mode which causes
338
	 * the device to enter a Connect/Disconnect loop
339 340 341 342 343 344
	 */
	if (dwc->revision < DWC3_REVISION_190A)
		reg |= DWC3_GCTL_U2RSTECN;

	dwc3_writel(dwc->regs, DWC3_GCTL, reg);

345 346 347
	ret = dwc3_event_buffers_setup(dwc);
	if (ret) {
		dev_err(dwc->dev, "failed to setup event buffers\n");
348
		goto err0;
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
	}

	return 0;

err0:
	return ret;
}

static void dwc3_core_exit(struct dwc3 *dwc)
{
	dwc3_event_buffers_cleanup(dwc);
}

#define DWC3_ALIGN_MASK		(16 - 1)

static int __devinit dwc3_probe(struct platform_device *pdev)
{
366
	struct device_node	*node = pdev->dev.of_node;
367 368
	struct resource		*res;
	struct dwc3		*dwc;
C
Chanho Park 已提交
369
	struct device		*dev = &pdev->dev;
370

371
	int			ret = -ENOMEM;
372 373

	void __iomem		*regs;
374 375
	void			*mem;

376 377
	u8			mode;

C
Chanho Park 已提交
378
	mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
379
	if (!mem) {
C
Chanho Park 已提交
380 381
		dev_err(dev, "not enough memory\n");
		return -ENOMEM;
382 383 384 385
	}
	dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
	dwc->mem = mem;

386
	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
387
	if (!res) {
388
		dev_err(dev, "missing IRQ\n");
C
Chanho Park 已提交
389
		return -ENODEV;
390
	}
391 392 393 394
	dwc->xhci_resources[1].start = res->start;
	dwc->xhci_resources[1].end = res->end;
	dwc->xhci_resources[1].flags = res->flags;
	dwc->xhci_resources[1].name = res->name;
395

396 397 398 399 400
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(dev, "missing memory resource\n");
		return -ENODEV;
	}
401
	dwc->xhci_resources[0].start = res->start;
402 403
	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
					DWC3_XHCI_REGS_END;
404 405
	dwc->xhci_resources[0].flags = res->flags;
	dwc->xhci_resources[0].name = res->name;
406 407 408 409 410 411 412

	 /*
	  * Request memory region but exclude xHCI regs,
	  * since it will be requested by the xhci-plat driver.
	  */
	res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START,
			resource_size(res) - DWC3_GLOBALS_REGS_START,
C
Chanho Park 已提交
413
			dev_name(dev));
414
	if (!res) {
C
Chanho Park 已提交
415 416
		dev_err(dev, "can't request mem region\n");
		return -ENOMEM;
417 418
	}

419
	regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
420
	if (!regs) {
C
Chanho Park 已提交
421 422
		dev_err(dev, "ioremap failed\n");
		return -ENOMEM;
423 424
	}

F
Felipe Balbi 已提交
425 426 427 428 429 430 431 432 433 434 435 436
	dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
	if (IS_ERR_OR_NULL(dwc->usb2_phy)) {
		dev_err(dev, "no usb2 phy configured\n");
		return -EPROBE_DEFER;
	}

	dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
	if (IS_ERR_OR_NULL(dwc->usb3_phy)) {
		dev_err(dev, "no usb3 phy configured\n");
		return -EPROBE_DEFER;
	}

437 438 439 440 441
	spin_lock_init(&dwc->lock);
	platform_set_drvdata(pdev, dwc);

	dwc->regs	= regs;
	dwc->regs_size	= resource_size(res);
C
Chanho Park 已提交
442
	dwc->dev	= dev;
443

444 445 446 447 448 449 450 451 452 453 454
	if (!strncmp("super", maximum_speed, 5))
		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
	else if (!strncmp("high", maximum_speed, 4))
		dwc->maximum_speed = DWC3_DCFG_HIGHSPEED;
	else if (!strncmp("full", maximum_speed, 4))
		dwc->maximum_speed = DWC3_DCFG_FULLSPEED1;
	else if (!strncmp("low", maximum_speed, 3))
		dwc->maximum_speed = DWC3_DCFG_LOWSPEED;
	else
		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;

455 456 457
	if (of_get_property(node, "tx-fifo-resize", NULL))
		dwc->needs_fifo_resize = true;

C
Chanho Park 已提交
458 459 460
	pm_runtime_enable(dev);
	pm_runtime_get_sync(dev);
	pm_runtime_forbid(dev);
461

462 463 464 465 466 467 468
	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
	if (ret) {
		dev_err(dwc->dev, "failed to allocate event buffers\n");
		ret = -ENOMEM;
		goto err0;
	}

469 470
	ret = dwc3_core_init(dwc);
	if (ret) {
C
Chanho Park 已提交
471
		dev_err(dev, "failed to initialize core\n");
472
		goto err0;
473 474
	}

475 476 477 478
	mode = DWC3_MODE(dwc->hwparams.hwparams0);

	switch (mode) {
	case DWC3_MODE_DEVICE:
479
		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
480 481
		ret = dwc3_gadget_init(dwc);
		if (ret) {
C
Chanho Park 已提交
482 483
			dev_err(dev, "failed to initialize gadget\n");
			goto err1;
484
		}
F
Felipe Balbi 已提交
485 486
		break;
	case DWC3_MODE_HOST:
487
		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
F
Felipe Balbi 已提交
488 489
		ret = dwc3_host_init(dwc);
		if (ret) {
C
Chanho Park 已提交
490 491
			dev_err(dev, "failed to initialize host\n");
			goto err1;
F
Felipe Balbi 已提交
492 493 494
		}
		break;
	case DWC3_MODE_DRD:
495
		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
F
Felipe Balbi 已提交
496 497
		ret = dwc3_host_init(dwc);
		if (ret) {
C
Chanho Park 已提交
498 499
			dev_err(dev, "failed to initialize host\n");
			goto err1;
F
Felipe Balbi 已提交
500 501
		}

502 503
		ret = dwc3_gadget_init(dwc);
		if (ret) {
C
Chanho Park 已提交
504 505
			dev_err(dev, "failed to initialize gadget\n");
			goto err1;
506
		}
507 508
		break;
	default:
C
Chanho Park 已提交
509 510
		dev_err(dev, "Unsupported mode of operation %d\n", mode);
		goto err1;
511
	}
512
	dwc->mode = mode;
513 514 515

	ret = dwc3_debugfs_init(dwc);
	if (ret) {
C
Chanho Park 已提交
516 517
		dev_err(dev, "failed to initialize debugfs\n");
		goto err2;
518 519
	}

C
Chanho Park 已提交
520
	pm_runtime_allow(dev);
521 522 523

	return 0;

C
Chanho Park 已提交
524
err2:
525 526
	switch (mode) {
	case DWC3_MODE_DEVICE:
527
		dwc3_gadget_exit(dwc);
528
		break;
F
Felipe Balbi 已提交
529 530 531 532 533
	case DWC3_MODE_HOST:
		dwc3_host_exit(dwc);
		break;
	case DWC3_MODE_DRD:
		dwc3_host_exit(dwc);
534
		dwc3_gadget_exit(dwc);
F
Felipe Balbi 已提交
535
		break;
536 537 538 539
	default:
		/* do nothing */
		break;
	}
540 541

err1:
C
Chanho Park 已提交
542
	dwc3_core_exit(dwc);
543

544 545 546
err0:
	dwc3_free_event_buffers(dwc);

547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
	return ret;
}

static int __devexit dwc3_remove(struct platform_device *pdev)
{
	struct dwc3	*dwc = platform_get_drvdata(pdev);
	struct resource	*res;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

	pm_runtime_put(&pdev->dev);
	pm_runtime_disable(&pdev->dev);

	dwc3_debugfs_exit(dwc);

562 563
	switch (dwc->mode) {
	case DWC3_MODE_DEVICE:
564
		dwc3_gadget_exit(dwc);
565
		break;
F
Felipe Balbi 已提交
566 567 568 569 570
	case DWC3_MODE_HOST:
		dwc3_host_exit(dwc);
		break;
	case DWC3_MODE_DRD:
		dwc3_host_exit(dwc);
571
		dwc3_gadget_exit(dwc);
F
Felipe Balbi 已提交
572
		break;
573 574 575 576
	default:
		/* do nothing */
		break;
	}
577 578 579 580 581 582 583 584 585 586 587 588 589 590

	dwc3_core_exit(dwc);

	return 0;
}

static struct platform_driver dwc3_driver = {
	.probe		= dwc3_probe,
	.remove		= __devexit_p(dwc3_remove),
	.driver		= {
		.name	= "dwc3",
	},
};

591 592
module_platform_driver(dwc3_driver);

593
MODULE_ALIAS("platform:dwc3");
594 595 596
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");