omap2430.c 17.2 KB
Newer Older
F
Felipe Balbi 已提交
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
/*
 * Copyright (C) 2005-2007 by Texas Instruments
 * Some code has been taken from tusb6010.c
 * Copyrights for that are attributable to:
 * Copyright (C) 2006 Nokia Corporation
 * Tony Lindgren <tony@atomide.com>
 *
 * This file is part of the Inventra Controller Driver for Linux.
 *
 * The Inventra Controller Driver for Linux is free software; you
 * can redistribute it and/or modify it under the terms of the GNU
 * General Public License version 2 as published by the Free Software
 * Foundation.
 *
 * The Inventra Controller Driver for Linux is distributed in
 * the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 * License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with The Inventra Controller Driver for Linux ; if not,
 * write to the Free Software Foundation, Inc., 59 Temple Place,
 * Suite 330, Boston, MA  02111-1307  USA
 *
 */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/io.h>
33
#include <linux/of.h>
34 35
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
36 37
#include <linux/pm_runtime.h>
#include <linux/err.h>
38
#include <linux/delay.h>
39
#include <linux/usb/musb-omap.h>
F
Felipe Balbi 已提交
40 41 42 43

#include "musb_core.h"
#include "omap2430.h"

44 45 46
struct omap2430_glue {
	struct device		*dev;
	struct platform_device	*musb;
47
	enum omap_musb_vbus_id_status status;
48
	struct work_struct	omap_musb_mailbox_work;
49
	u32 __iomem		*control_otghs;
50
};
51
#define glue_to_musb(g)		platform_get_drvdata(g->musb)
52

53 54
struct omap2430_glue		*_glue;

F
Felipe Balbi 已提交
55 56
static struct timer_list musb_idle_timer;

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
/**
 * omap4_usb_phy_mailbox - write to usb otg mailbox
 * @glue: struct omap2430_glue *
 * @val: the value to be written to the mailbox
 *
 * On detection of a device (ID pin is grounded), this API should be called
 * to set AVALID, VBUSVALID and ID pin is grounded.
 *
 * When OMAP is connected to a host (OMAP in device mode), this API
 * is called to set AVALID, VBUSVALID and ID pin in high impedance.
 *
 * XXX: This function will be removed once we have a seperate driver for
 * control module
 */
static void omap4_usb_phy_mailbox(struct omap2430_glue *glue, u32 val)
{
	if (glue->control_otghs)
		writel(val, glue->control_otghs);
}

F
Felipe Balbi 已提交
77 78 79 80 81 82 83 84 85
static void musb_do_idle(unsigned long _musb)
{
	struct musb	*musb = (void *)_musb;
	unsigned long	flags;
	u8	power;
	u8	devctl;

	spin_lock_irqsave(&musb->lock, flags);

86
	switch (musb->xceiv->state) {
F
Felipe Balbi 已提交
87 88 89 90
	case OTG_STATE_A_WAIT_BCON:

		devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
		if (devctl & MUSB_DEVCTL_BDEVICE) {
91
			musb->xceiv->state = OTG_STATE_B_IDLE;
F
Felipe Balbi 已提交
92 93
			MUSB_DEV_MODE(musb);
		} else {
94
			musb->xceiv->state = OTG_STATE_A_IDLE;
F
Felipe Balbi 已提交
95 96 97 98 99 100 101 102
			MUSB_HST_MODE(musb);
		}
		break;
	case OTG_STATE_A_SUSPEND:
		/* finish RESUME signaling? */
		if (musb->port1_status & MUSB_PORT_STAT_RESUME) {
			power = musb_readb(musb->mregs, MUSB_POWER);
			power &= ~MUSB_POWER_RESUME;
103
			dev_dbg(musb->controller, "root port resume stopped, power %02x\n", power);
F
Felipe Balbi 已提交
104 105 106 107 108 109 110
			musb_writeb(musb->mregs, MUSB_POWER, power);
			musb->is_active = 1;
			musb->port1_status &= ~(USB_PORT_STAT_SUSPEND
						| MUSB_PORT_STAT_RESUME);
			musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
			usb_hcd_poll_rh_status(musb_to_hcd(musb));
			/* NOTE: it might really be A_WAIT_BCON ... */
111
			musb->xceiv->state = OTG_STATE_A_HOST;
F
Felipe Balbi 已提交
112 113 114 115 116
		}
		break;
	case OTG_STATE_A_HOST:
		devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
		if (devctl &  MUSB_DEVCTL_BDEVICE)
117
			musb->xceiv->state = OTG_STATE_B_IDLE;
F
Felipe Balbi 已提交
118
		else
119
			musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
F
Felipe Balbi 已提交
120 121 122 123 124 125 126
	default:
		break;
	}
	spin_unlock_irqrestore(&musb->lock, flags);
}


127
static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
F
Felipe Balbi 已提交
128 129 130 131 132 133 134 135 136
{
	unsigned long		default_timeout = jiffies + msecs_to_jiffies(3);
	static unsigned long	last_timer;

	if (timeout == 0)
		timeout = default_timeout;

	/* Never idle if active, or when VBUS timeout is not set as host */
	if (musb->is_active || ((musb->a_wait_bcon == 0)
137
			&& (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
138
		dev_dbg(musb->controller, "%s active, deleting timer\n",
139
			otg_state_string(musb->xceiv->state));
F
Felipe Balbi 已提交
140 141 142 143 144 145 146 147 148
		del_timer(&musb_idle_timer);
		last_timer = jiffies;
		return;
	}

	if (time_after(last_timer, timeout)) {
		if (!timer_pending(&musb_idle_timer))
			last_timer = timeout;
		else {
149
			dev_dbg(musb->controller, "Longer idle timer already pending, ignoring\n");
F
Felipe Balbi 已提交
150 151 152 153 154
			return;
		}
	}
	last_timer = timeout;

155
	dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n",
156
		otg_state_string(musb->xceiv->state),
F
Felipe Balbi 已提交
157 158 159 160
		(unsigned long)jiffies_to_msecs(timeout - jiffies));
	mod_timer(&musb_idle_timer, timeout);
}

161
static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
F
Felipe Balbi 已提交
162
{
163
	struct usb_otg	*otg = musb->xceiv->otg;
F
Felipe Balbi 已提交
164
	u8		devctl;
165
	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
F
Felipe Balbi 已提交
166 167 168 169 170 171 172 173
	/* HDRC controls CPEN, but beware current surges during device
	 * connect.  They can trigger transient overcurrent conditions
	 * that must be ignored.
	 */

	devctl = musb_readb(musb->mregs, MUSB_DEVCTL);

	if (is_on) {
174
		if (musb->xceiv->state == OTG_STATE_A_IDLE) {
175
			int loops = 100;
176 177 178 179 180 181 182 183 184
			/* start the session */
			devctl |= MUSB_DEVCTL_SESSION;
			musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
			/*
			 * Wait for the musb to set as A device to enable the
			 * VBUS
			 */
			while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {

185
				mdelay(5);
186 187
				cpu_relax();

188 189
				if (time_after(jiffies, timeout)
				    || loops-- <= 0) {
190 191 192 193 194 195
					dev_err(musb->controller,
					"configured as A device timeout");
					break;
				}
			}

196
			if (otg->set_vbus)
197
				otg_set_vbus(otg, 1);
198 199
		} else {
			musb->is_active = 1;
200
			otg->default_a = 1;
201 202 203 204
			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
			devctl |= MUSB_DEVCTL_SESSION;
			MUSB_HST_MODE(musb);
		}
F
Felipe Balbi 已提交
205 206 207 208 209 210 211
	} else {
		musb->is_active = 0;

		/* NOTE:  we're skipping A_WAIT_VFALL -> A_IDLE and
		 * jumping right to B_IDLE...
		 */

212
		otg->default_a = 0;
213
		musb->xceiv->state = OTG_STATE_B_IDLE;
F
Felipe Balbi 已提交
214 215 216 217 218 219
		devctl &= ~MUSB_DEVCTL_SESSION;

		MUSB_DEV_MODE(musb);
	}
	musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);

220
	dev_dbg(musb->controller, "VBUS %s, devctl %02x "
F
Felipe Balbi 已提交
221
		/* otg %3x conf %08x prcm %08x */ "\n",
222
		otg_state_string(musb->xceiv->state),
F
Felipe Balbi 已提交
223 224 225
		musb_readb(musb->mregs, MUSB_DEVCTL));
}

226
static int omap2430_musb_set_mode(struct musb *musb, u8 musb_mode)
F
Felipe Balbi 已提交
227 228 229 230 231 232
{
	u8	devctl = musb_readb(musb->mregs, MUSB_DEVCTL);

	devctl |= MUSB_DEVCTL_SESSION;
	musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);

D
David Brownell 已提交
233
	return 0;
F
Felipe Balbi 已提交
234 235
}

236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
static inline void omap2430_low_level_exit(struct musb *musb)
{
	u32 l;

	/* in any role */
	l = musb_readl(musb->mregs, OTG_FORCESTDBY);
	l |= ENABLEFORCE;	/* enable MSTANDBY */
	musb_writel(musb->mregs, OTG_FORCESTDBY, l);
}

static inline void omap2430_low_level_init(struct musb *musb)
{
	u32 l;

	l = musb_readl(musb->mregs, OTG_FORCESTDBY);
	l &= ~ENABLEFORCE;	/* disable MSTANDBY */
	musb_writel(musb->mregs, OTG_FORCESTDBY, l);
}

255
void omap_musb_mailbox(enum omap_musb_vbus_id_status status)
256
{
257 258
	struct omap2430_glue	*glue = _glue;
	struct musb		*musb = glue_to_musb(glue);
259

260 261 262 263 264
	glue->status = status;
	if (!musb) {
		dev_err(glue->dev, "musb core is not yet ready\n");
		return;
	}
265

266
	schedule_work(&glue->omap_musb_mailbox_work);
267
}
268
EXPORT_SYMBOL_GPL(omap_musb_mailbox);
269

270
static void omap_musb_set_mailbox(struct omap2430_glue *glue)
271
{
272
	u32 val;
273
	struct musb *musb = glue_to_musb(glue);
274 275 276
	struct device *dev = musb->controller;
	struct musb_hdrc_platform_data *pdata = dev->platform_data;
	struct omap_musb_board_data *data = pdata->board_data;
277
	struct usb_otg *otg = musb->xceiv->otg;
278

279 280 281
	switch (glue->status) {
	case OMAP_MUSB_ID_GROUND:
		dev_dbg(dev, "ID GND\n");
282

283 284
		otg->default_a = true;
		musb->xceiv->state = OTG_STATE_A_IDLE;
285
		musb->xceiv->last_event = USB_EVENT_ID;
286
		if (musb->gadget_driver) {
287
			pm_runtime_get_sync(dev);
288 289
			val = AVALID | VBUSVALID;
			omap4_usb_phy_mailbox(glue, val);
290
			omap2430_musb_set_vbus(musb, 1);
291 292 293
		}
		break;

294 295
	case OMAP_MUSB_VBUS_VALID:
		dev_dbg(dev, "VBUS Connect\n");
296

297 298
		otg->default_a = false;
		musb->xceiv->state = OTG_STATE_B_IDLE;
299
		musb->xceiv->last_event = USB_EVENT_VBUS;
300
		if (musb->gadget_driver)
301
			pm_runtime_get_sync(dev);
302 303
		val = IDDIG | AVALID | VBUSVALID;
		omap4_usb_phy_mailbox(glue, val);
304 305
		break;

306 307 308
	case OMAP_MUSB_ID_FLOAT:
	case OMAP_MUSB_VBUS_OFF:
		dev_dbg(dev, "VBUS Disconnect\n");
309

310
		musb->xceiv->last_event = USB_EVENT_NONE;
311 312 313 314
		if (musb->gadget_driver) {
			pm_runtime_mark_last_busy(dev);
			pm_runtime_put_autosuspend(dev);
		}
315

316
		if (data->interface_type == MUSB_INTERFACE_UTMI) {
317 318
			if (musb->xceiv->otg->set_vbus)
				otg_set_vbus(musb->xceiv->otg, 0);
319
		}
320 321
		val = SESSEND | IDDIG;
		omap4_usb_phy_mailbox(glue, val);
322 323
		break;
	default:
324
		dev_dbg(dev, "ID float\n");
325 326 327
	}
}

328 329 330 331 332 333 334 335

static void omap_musb_mailbox_work(struct work_struct *mailbox_work)
{
	struct omap2430_glue *glue = container_of(mailbox_work,
				struct omap2430_glue, omap_musb_mailbox_work);
	omap_musb_set_mailbox(glue);
}

336
static int omap2430_musb_init(struct musb *musb)
F
Felipe Balbi 已提交
337
{
338 339
	u32 l;
	int status = 0;
340
	struct device *dev = musb->controller;
341
	struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
342 343
	struct musb_hdrc_platform_data *plat = dev->platform_data;
	struct omap_musb_board_data *data = plat->board_data;
F
Felipe Balbi 已提交
344

345 346 347 348
	/* We require some kind of external transceiver, hooked
	 * up through ULPI.  TWL4030-family PMICs include one,
	 * which needs a driver, drivers aren't always needed.
	 */
349
	musb->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
350
	if (IS_ERR_OR_NULL(musb->xceiv)) {
351 352 353 354
		pr_err("HS USB OTG: no transceiver configured\n");
		return -ENODEV;
	}

355 356
	status = pm_runtime_get_sync(dev);
	if (status < 0) {
357
		dev_err(dev, "pm_runtime_get_sync FAILED %d\n", status);
358 359
		goto err1;
	}
F
Felipe Balbi 已提交
360

361
	l = musb_readl(musb->mregs, OTG_INTERFSEL);
362 363 364 365 366 367 368 369 370

	if (data->interface_type == MUSB_INTERFACE_UTMI) {
		/* OMAP4 uses Internal PHY GS70 which uses UTMI interface */
		l &= ~ULPI_12PIN;       /* Disable ULPI */
		l |= UTMI_8BIT;         /* Enable UTMI  */
	} else {
		l |= ULPI_12PIN;
	}

371
	musb_writel(musb->mregs, OTG_INTERFSEL, l);
F
Felipe Balbi 已提交
372 373 374

	pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
			"sysstatus 0x%x, intrfsel 0x%x, simenable  0x%x\n",
375 376 377 378 379
			musb_readl(musb->mregs, OTG_REVISION),
			musb_readl(musb->mregs, OTG_SYSCONFIG),
			musb_readl(musb->mregs, OTG_SYSSTATUS),
			musb_readl(musb->mregs, OTG_INTERFSEL),
			musb_readl(musb->mregs, OTG_SIMENABLE));
F
Felipe Balbi 已提交
380 381 382

	setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);

383 384 385
	if (glue->status != OMAP_MUSB_UNKNOWN)
		omap_musb_set_mailbox(glue);

386
	pm_runtime_put_noidle(musb->controller);
F
Felipe Balbi 已提交
387
	return 0;
388 389 390

err1:
	return status;
F
Felipe Balbi 已提交
391 392
}

393 394 395
static void omap2430_musb_enable(struct musb *musb)
{
	u8		devctl;
396
	u32		val;
397 398
	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
	struct device *dev = musb->controller;
399
	struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
400 401 402
	struct musb_hdrc_platform_data *pdata = dev->platform_data;
	struct omap_musb_board_data *data = pdata->board_data;

403
	switch (glue->status) {
404

405
	case OMAP_MUSB_ID_GROUND:
406 407
		val = AVALID | VBUSVALID;
		omap4_usb_phy_mailbox(glue, val);
408 409 410 411 412 413 414 415 416 417 418 419 420
		if (data->interface_type != MUSB_INTERFACE_UTMI)
			break;
		devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
		/* start the session */
		devctl |= MUSB_DEVCTL_SESSION;
		musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
		while (musb_readb(musb->mregs, MUSB_DEVCTL) &
				MUSB_DEVCTL_BDEVICE) {
			cpu_relax();

			if (time_after(jiffies, timeout)) {
				dev_err(dev, "configured as A device timeout");
				break;
421 422 423 424
			}
		}
		break;

425
	case OMAP_MUSB_VBUS_VALID:
426 427
		val = IDDIG | AVALID | VBUSVALID;
		omap4_usb_phy_mailbox(glue, val);
428 429 430 431 432 433 434 435 436
		break;

	default:
		break;
	}
}

static void omap2430_musb_disable(struct musb *musb)
{
437
	u32 val;
438 439 440
	struct device *dev = musb->controller;
	struct omap2430_glue *glue = dev_get_drvdata(dev->parent);

441 442 443 444
	if (glue->status != OMAP_MUSB_UNKNOWN) {
		val = SESSEND | IDDIG;
		omap4_usb_phy_mailbox(glue, val);
	}
F
Felipe Balbi 已提交
445 446
}

447
static int omap2430_musb_exit(struct musb *musb)
F
Felipe Balbi 已提交
448
{
449
	del_timer_sync(&musb_idle_timer);
F
Felipe Balbi 已提交
450

451 452
	omap2430_low_level_exit(musb);

F
Felipe Balbi 已提交
453 454
	return 0;
}
455

456
static const struct musb_platform_ops omap2430_ops = {
457 458 459 460 461 462 463
	.init		= omap2430_musb_init,
	.exit		= omap2430_musb_exit,

	.set_mode	= omap2430_musb_set_mode,
	.try_idle	= omap2430_musb_try_idle,

	.set_vbus	= omap2430_musb_set_vbus,
464 465 466

	.enable		= omap2430_musb_enable,
	.disable	= omap2430_musb_disable,
467
};
468 469 470

static u64 omap2430_dmamask = DMA_BIT_MASK(32);

471
static int __devinit omap2430_probe(struct platform_device *pdev)
472 473
{
	struct musb_hdrc_platform_data	*pdata = pdev->dev.platform_data;
474
	struct omap_musb_board_data	*data;
475
	struct platform_device		*musb;
476
	struct omap2430_glue		*glue;
477 478
	struct device_node		*np = pdev->dev.of_node;
	struct musb_hdrc_config		*config;
479
	struct resource			*res;
480
	int				ret = -ENOMEM;
481
	int				musbid;
482

483
	glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
484 485 486 487 488
	if (!glue) {
		dev_err(&pdev->dev, "failed to allocate glue context\n");
		goto err0;
	}

489 490 491 492 493 494 495 496 497
	/* get the musb id */
	musbid = musb_get_id(&pdev->dev, GFP_KERNEL);
	if (musbid < 0) {
		dev_err(&pdev->dev, "failed to allocate musb id\n");
		ret = -ENOMEM;
		goto err0;
	}

	musb = platform_device_alloc("musb-hdrc", musbid);
498 499
	if (!musb) {
		dev_err(&pdev->dev, "failed to allocate musb device\n");
500
		goto err1;
501 502
	}

503
	musb->id			= musbid;
504 505 506 507
	musb->dev.parent		= &pdev->dev;
	musb->dev.dma_mask		= &omap2430_dmamask;
	musb->dev.coherent_dma_mask	= omap2430_dmamask;

508 509
	glue->dev			= &pdev->dev;
	glue->musb			= musb;
510
	glue->status			= OMAP_MUSB_UNKNOWN;
511

512 513 514 515 516 517
	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);

	glue->control_otghs = devm_request_and_ioremap(&pdev->dev, res);
	if (glue->control_otghs == NULL)
		dev_dbg(&pdev->dev, "Failed to obtain control memory\n");

518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
	if (np) {
		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
		if (!pdata) {
			dev_err(&pdev->dev,
				"failed to allocate musb platfrom data\n");
			ret = -ENOMEM;
			goto err1;
		}

		data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
		if (!data) {
			dev_err(&pdev->dev,
					"failed to allocate musb board data\n");
			ret = -ENOMEM;
			goto err1;
		}

		config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
		if (!data) {
			dev_err(&pdev->dev,
				"failed to allocate musb hdrc config\n");
			goto err1;
		}

		of_property_read_u32(np, "mode", (u32 *)&pdata->mode);
		of_property_read_u32(np, "interface_type",
						(u32 *)&data->interface_type);
		of_property_read_u32(np, "num_eps", (u32 *)&config->num_eps);
		of_property_read_u32(np, "ram_bits", (u32 *)&config->ram_bits);
		of_property_read_u32(np, "power", (u32 *)&pdata->power);
		config->multipoint = of_property_read_bool(np, "multipoint");

		pdata->board_data	= data;
		pdata->config		= config;
	}

554 555
	pdata->platform_ops		= &omap2430_ops;

556
	platform_set_drvdata(pdev, glue);
557

558 559 560 561 562 563
	/*
	 * REVISIT if we ever have two instances of the wrapper, we will be
	 * in big trouble
	 */
	_glue	= glue;

564 565
	INIT_WORK(&glue->omap_musb_mailbox_work, omap_musb_mailbox_work);

566 567 568 569
	ret = platform_device_add_resources(musb, pdev->resource,
			pdev->num_resources);
	if (ret) {
		dev_err(&pdev->dev, "failed to add resources\n");
570
		goto err2;
571 572 573 574 575
	}

	ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
	if (ret) {
		dev_err(&pdev->dev, "failed to add platform_data\n");
576
		goto err2;
577 578
	}

579 580
	pm_runtime_enable(&pdev->dev);

581 582 583
	ret = platform_device_add(musb);
	if (ret) {
		dev_err(&pdev->dev, "failed to register musb device\n");
584
		goto err2;
585 586
	}

587
	return 0;
588

589
err2:
590
	platform_device_put(musb);
591

592 593 594
err1:
	musb_put_id(&pdev->dev, musbid);

595 596 597 598
err0:
	return ret;
}

599
static int __devexit omap2430_remove(struct platform_device *pdev)
600
{
601
	struct omap2430_glue		*glue = platform_get_drvdata(pdev);
602

603
	cancel_work_sync(&glue->omap_musb_mailbox_work);
604
	musb_put_id(&pdev->dev, glue->musb->id);
605
	platform_device_unregister(glue->musb);
606 607 608 609

	return 0;
}

610 611
#ifdef CONFIG_PM

612
static int omap2430_runtime_suspend(struct device *dev)
613 614 615 616
{
	struct omap2430_glue		*glue = dev_get_drvdata(dev);
	struct musb			*musb = glue_to_musb(glue);

617 618 619
	if (musb) {
		musb->context.otg_interfsel = musb_readl(musb->mregs,
				OTG_INTERFSEL);
620

621 622 623
		omap2430_low_level_exit(musb);
		usb_phy_set_suspend(musb->xceiv, 1);
	}
624 625 626 627

	return 0;
}

628
static int omap2430_runtime_resume(struct device *dev)
629 630 631 632
{
	struct omap2430_glue		*glue = dev_get_drvdata(dev);
	struct musb			*musb = glue_to_musb(glue);

633 634 635 636
	if (musb) {
		omap2430_low_level_init(musb);
		musb_writel(musb->mregs, OTG_INTERFSEL,
				musb->context.otg_interfsel);
637

638 639
		usb_phy_set_suspend(musb->xceiv, 0);
	}
640 641 642 643 644

	return 0;
}

static struct dev_pm_ops omap2430_pm_ops = {
645 646
	.runtime_suspend = omap2430_runtime_suspend,
	.runtime_resume = omap2430_runtime_resume,
647 648 649 650 651 652 653
};

#define DEV_PM_OPS	(&omap2430_pm_ops)
#else
#define DEV_PM_OPS	NULL
#endif

654 655 656 657 658 659 660 661 662 663 664 665 666
#ifdef CONFIG_OF
static const struct of_device_id omap2430_id_table[] = {
	{
		.compatible = "ti,omap4-musb"
	},
	{
		.compatible = "ti,omap3-musb"
	},
	{},
};
MODULE_DEVICE_TABLE(of, omap2430_id_table);
#endif

667
static struct platform_driver omap2430_driver = {
668 669
	.probe		= omap2430_probe,
	.remove		= __devexit_p(omap2430_remove),
670 671
	.driver		= {
		.name	= "musb-omap2430",
672
		.pm	= DEV_PM_OPS,
673
		.of_match_table = of_match_ptr(omap2430_id_table),
674 675 676 677 678 679 680 681 682
	},
};

MODULE_DESCRIPTION("OMAP2PLUS MUSB Glue Layer");
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
MODULE_LICENSE("GPL v2");

static int __init omap2430_init(void)
{
683
	return platform_driver_register(&omap2430_driver);
684
}
685
subsys_initcall(omap2430_init);
686 687 688 689 690 691

static void __exit omap2430_exit(void)
{
	platform_driver_unregister(&omap2430_driver);
}
module_exit(omap2430_exit);