xref: /rk3399_rockchip-uboot/drivers/usb/musb-new/musb_dsps.c (revision 73eed452b9c9827474c0789c30729dca6fcf061d)
137931f02SIlya Yanok /*
237931f02SIlya Yanok  * Texas Instruments DSPS platforms "glue layer"
337931f02SIlya Yanok  *
437931f02SIlya Yanok  * Copyright (C) 2012, by Texas Instruments
537931f02SIlya Yanok  *
637931f02SIlya Yanok  * Based on the am35x "glue layer" code.
737931f02SIlya Yanok  *
837931f02SIlya Yanok  * This file is part of the Inventra Controller Driver for Linux.
937931f02SIlya Yanok  *
105b8031ccSTom Rini  * SPDX-License-Identifier:	GPL-2.0
1137931f02SIlya Yanok  *
1237931f02SIlya Yanok  * musb_dsps.c will be a common file for all the TI DSPS platforms
1337931f02SIlya Yanok  * such as dm64x, dm36x, dm35x, da8x, am35x and ti81x.
1437931f02SIlya Yanok  * For now only ti81x is using this and in future davinci.c, am35x.c
1537931f02SIlya Yanok  * da8xx.c would be merged to this file after testing.
1637931f02SIlya Yanok  */
1737931f02SIlya Yanok 
1837931f02SIlya Yanok #ifndef __UBOOT__
1937931f02SIlya Yanok #include <linux/init.h>
2037931f02SIlya Yanok #include <linux/io.h>
2137931f02SIlya Yanok #include <linux/err.h>
2237931f02SIlya Yanok #include <linux/platform_device.h>
2337931f02SIlya Yanok #include <linux/dma-mapping.h>
2437931f02SIlya Yanok #include <linux/pm_runtime.h>
2537931f02SIlya Yanok #include <linux/module.h>
2637931f02SIlya Yanok 
2737931f02SIlya Yanok #include <linux/of.h>
2837931f02SIlya Yanok #include <linux/of_device.h>
2937931f02SIlya Yanok #include <linux/of_address.h>
3037931f02SIlya Yanok 
3137931f02SIlya Yanok #include <plat/usb.h>
3237931f02SIlya Yanok #else
3337931f02SIlya Yanok #include <common.h>
3437931f02SIlya Yanok #include <asm/omap_musb.h>
3537931f02SIlya Yanok #include "linux-compat.h"
3637931f02SIlya Yanok #endif
3737931f02SIlya Yanok 
3837931f02SIlya Yanok #include "musb_core.h"
3937931f02SIlya Yanok 
4037931f02SIlya Yanok /**
4137931f02SIlya Yanok  * avoid using musb_readx()/musb_writex() as glue layer should not be
4237931f02SIlya Yanok  * dependent on musb core layer symbols.
4337931f02SIlya Yanok  */
dsps_readb(const void __iomem * addr,unsigned offset)4437931f02SIlya Yanok static inline u8 dsps_readb(const void __iomem *addr, unsigned offset)
4537931f02SIlya Yanok 	{ return __raw_readb(addr + offset); }
4637931f02SIlya Yanok 
dsps_readl(const void __iomem * addr,unsigned offset)4737931f02SIlya Yanok static inline u32 dsps_readl(const void __iomem *addr, unsigned offset)
4837931f02SIlya Yanok 	{ return __raw_readl(addr + offset); }
4937931f02SIlya Yanok 
dsps_writeb(void __iomem * addr,unsigned offset,u8 data)5037931f02SIlya Yanok static inline void dsps_writeb(void __iomem *addr, unsigned offset, u8 data)
5137931f02SIlya Yanok 	{ __raw_writeb(data, addr + offset); }
5237931f02SIlya Yanok 
dsps_writel(void __iomem * addr,unsigned offset,u32 data)5337931f02SIlya Yanok static inline void dsps_writel(void __iomem *addr, unsigned offset, u32 data)
5437931f02SIlya Yanok 	{ __raw_writel(data, addr + offset); }
5537931f02SIlya Yanok 
5637931f02SIlya Yanok /**
5737931f02SIlya Yanok  * DSPS musb wrapper register offset.
5837931f02SIlya Yanok  * FIXME: This should be expanded to have all the wrapper registers from TI DSPS
5937931f02SIlya Yanok  * musb ips.
6037931f02SIlya Yanok  */
6137931f02SIlya Yanok struct dsps_musb_wrapper {
6237931f02SIlya Yanok 	u16	revision;
6337931f02SIlya Yanok 	u16	control;
6437931f02SIlya Yanok 	u16	status;
6537931f02SIlya Yanok 	u16	eoi;
6637931f02SIlya Yanok 	u16	epintr_set;
6737931f02SIlya Yanok 	u16	epintr_clear;
6837931f02SIlya Yanok 	u16	epintr_status;
6937931f02SIlya Yanok 	u16	coreintr_set;
7037931f02SIlya Yanok 	u16	coreintr_clear;
7137931f02SIlya Yanok 	u16	coreintr_status;
7237931f02SIlya Yanok 	u16	phy_utmi;
7337931f02SIlya Yanok 	u16	mode;
7437931f02SIlya Yanok 
7537931f02SIlya Yanok 	/* bit positions for control */
7637931f02SIlya Yanok 	unsigned	reset:5;
7737931f02SIlya Yanok 
7837931f02SIlya Yanok 	/* bit positions for interrupt */
7937931f02SIlya Yanok 	unsigned	usb_shift:5;
8037931f02SIlya Yanok 	u32		usb_mask;
8137931f02SIlya Yanok 	u32		usb_bitmap;
8237931f02SIlya Yanok 	unsigned	drvvbus:5;
8337931f02SIlya Yanok 
8437931f02SIlya Yanok 	unsigned	txep_shift:5;
8537931f02SIlya Yanok 	u32		txep_mask;
8637931f02SIlya Yanok 	u32		txep_bitmap;
8737931f02SIlya Yanok 
8837931f02SIlya Yanok 	unsigned	rxep_shift:5;
8937931f02SIlya Yanok 	u32		rxep_mask;
9037931f02SIlya Yanok 	u32		rxep_bitmap;
9137931f02SIlya Yanok 
9237931f02SIlya Yanok 	/* bit positions for phy_utmi */
9337931f02SIlya Yanok 	unsigned	otg_disable:5;
9437931f02SIlya Yanok 
9537931f02SIlya Yanok 	/* bit positions for mode */
9637931f02SIlya Yanok 	unsigned	iddig:5;
9737931f02SIlya Yanok 	/* miscellaneous stuff */
9837931f02SIlya Yanok 	u32		musb_core_offset;
9937931f02SIlya Yanok 	u8		poll_seconds;
10037931f02SIlya Yanok };
10137931f02SIlya Yanok 
10237931f02SIlya Yanok static const struct dsps_musb_wrapper ti81xx_driver_data __devinitconst = {
10337931f02SIlya Yanok 	.revision		= 0x00,
10437931f02SIlya Yanok 	.control		= 0x14,
10537931f02SIlya Yanok 	.status			= 0x18,
10637931f02SIlya Yanok 	.eoi			= 0x24,
10737931f02SIlya Yanok 	.epintr_set		= 0x38,
10837931f02SIlya Yanok 	.epintr_clear		= 0x40,
10937931f02SIlya Yanok 	.epintr_status		= 0x30,
11037931f02SIlya Yanok 	.coreintr_set		= 0x3c,
11137931f02SIlya Yanok 	.coreintr_clear		= 0x44,
11237931f02SIlya Yanok 	.coreintr_status	= 0x34,
11337931f02SIlya Yanok 	.phy_utmi		= 0xe0,
11437931f02SIlya Yanok 	.mode			= 0xe8,
11537931f02SIlya Yanok 	.reset			= 0,
11637931f02SIlya Yanok 	.otg_disable		= 21,
11737931f02SIlya Yanok 	.iddig			= 8,
11837931f02SIlya Yanok 	.usb_shift		= 0,
11937931f02SIlya Yanok 	.usb_mask		= 0x1ff,
12037931f02SIlya Yanok 	.usb_bitmap		= (0x1ff << 0),
12137931f02SIlya Yanok 	.drvvbus		= 8,
12237931f02SIlya Yanok 	.txep_shift		= 0,
12337931f02SIlya Yanok 	.txep_mask		= 0xffff,
12437931f02SIlya Yanok 	.txep_bitmap		= (0xffff << 0),
12537931f02SIlya Yanok 	.rxep_shift		= 16,
12637931f02SIlya Yanok 	.rxep_mask		= 0xfffe,
12737931f02SIlya Yanok 	.rxep_bitmap		= (0xfffe << 16),
12837931f02SIlya Yanok 	.musb_core_offset	= 0x400,
12937931f02SIlya Yanok 	.poll_seconds		= 2,
13037931f02SIlya Yanok };
13137931f02SIlya Yanok 
13237931f02SIlya Yanok /**
13337931f02SIlya Yanok  * DSPS glue structure.
13437931f02SIlya Yanok  */
13537931f02SIlya Yanok struct dsps_glue {
13637931f02SIlya Yanok 	struct device *dev;
13737931f02SIlya Yanok 	struct platform_device *musb;	/* child musb pdev */
13837931f02SIlya Yanok 	const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
13937931f02SIlya Yanok 	struct timer_list timer;	/* otg_workaround timer */
14037931f02SIlya Yanok };
14137931f02SIlya Yanok 
14237931f02SIlya Yanok /**
14337931f02SIlya Yanok  * dsps_musb_enable - enable interrupts
14437931f02SIlya Yanok  */
14515837236SHans de Goede #ifndef __UBOOT__
dsps_musb_enable(struct musb * musb)14637931f02SIlya Yanok static void dsps_musb_enable(struct musb *musb)
14715837236SHans de Goede #else
14815837236SHans de Goede static int dsps_musb_enable(struct musb *musb)
14915837236SHans de Goede #endif
15037931f02SIlya Yanok {
15137931f02SIlya Yanok #ifndef __UBOOT__
15237931f02SIlya Yanok 	struct device *dev = musb->controller;
15337931f02SIlya Yanok 	struct platform_device *pdev = to_platform_device(dev->parent);
15437931f02SIlya Yanok 	struct dsps_glue *glue = platform_get_drvdata(pdev);
15537931f02SIlya Yanok 	const struct dsps_musb_wrapper *wrp = glue->wrp;
15637931f02SIlya Yanok #else
15737931f02SIlya Yanok 	const struct dsps_musb_wrapper *wrp = &ti81xx_driver_data;
15837931f02SIlya Yanok #endif
15937931f02SIlya Yanok 	void __iomem *reg_base = musb->ctrl_base;
16037931f02SIlya Yanok 	u32 epmask, coremask;
16137931f02SIlya Yanok 
16237931f02SIlya Yanok 	/* Workaround: setup IRQs through both register sets. */
16337931f02SIlya Yanok 	epmask = ((musb->epmask & wrp->txep_mask) << wrp->txep_shift) |
16437931f02SIlya Yanok 	       ((musb->epmask & wrp->rxep_mask) << wrp->rxep_shift);
16537931f02SIlya Yanok 	coremask = (wrp->usb_bitmap & ~MUSB_INTR_SOF);
16637931f02SIlya Yanok 
16737931f02SIlya Yanok 	dsps_writel(reg_base, wrp->epintr_set, epmask);
16837931f02SIlya Yanok 	dsps_writel(reg_base, wrp->coreintr_set, coremask);
16937931f02SIlya Yanok 	/* Force the DRVVBUS IRQ so we can start polling for ID change. */
17037931f02SIlya Yanok #ifndef __UBOOT__
17137931f02SIlya Yanok 	if (is_otg_enabled(musb))
17237931f02SIlya Yanok 		dsps_writel(reg_base, wrp->coreintr_set,
17337931f02SIlya Yanok 			    (1 << wrp->drvvbus) << wrp->usb_shift);
17415837236SHans de Goede #else
17515837236SHans de Goede 	return 0;
17637931f02SIlya Yanok #endif
17737931f02SIlya Yanok }
17837931f02SIlya Yanok 
17937931f02SIlya Yanok /**
18037931f02SIlya Yanok  * dsps_musb_disable - disable HDRC and flush interrupts
18137931f02SIlya Yanok  */
dsps_musb_disable(struct musb * musb)18237931f02SIlya Yanok static void dsps_musb_disable(struct musb *musb)
18337931f02SIlya Yanok {
18437931f02SIlya Yanok #ifndef __UBOOT__
18537931f02SIlya Yanok 	struct device *dev = musb->controller;
18637931f02SIlya Yanok 	struct platform_device *pdev = to_platform_device(dev->parent);
18737931f02SIlya Yanok 	struct dsps_glue *glue = platform_get_drvdata(pdev);
18837931f02SIlya Yanok 	const struct dsps_musb_wrapper *wrp = glue->wrp;
18937931f02SIlya Yanok 	void __iomem *reg_base = musb->ctrl_base;
19037931f02SIlya Yanok 
19137931f02SIlya Yanok 	dsps_writel(reg_base, wrp->coreintr_clear, wrp->usb_bitmap);
19237931f02SIlya Yanok 	dsps_writel(reg_base, wrp->epintr_clear,
19337931f02SIlya Yanok 			 wrp->txep_bitmap | wrp->rxep_bitmap);
19437931f02SIlya Yanok 	dsps_writeb(musb->mregs, MUSB_DEVCTL, 0);
19537931f02SIlya Yanok 	dsps_writel(reg_base, wrp->eoi, 0);
19637931f02SIlya Yanok #endif
19737931f02SIlya Yanok }
19837931f02SIlya Yanok 
19937931f02SIlya Yanok #ifndef __UBOOT__
otg_timer(unsigned long _musb)20037931f02SIlya Yanok static void otg_timer(unsigned long _musb)
20137931f02SIlya Yanok {
20237931f02SIlya Yanok 	struct musb *musb = (void *)_musb;
20337931f02SIlya Yanok 	void __iomem *mregs = musb->mregs;
20437931f02SIlya Yanok 	struct device *dev = musb->controller;
20537931f02SIlya Yanok 	struct platform_device *pdev = to_platform_device(dev->parent);
20637931f02SIlya Yanok 	struct dsps_glue *glue = platform_get_drvdata(pdev);
20737931f02SIlya Yanok 	const struct dsps_musb_wrapper *wrp = glue->wrp;
20837931f02SIlya Yanok 	u8 devctl;
20937931f02SIlya Yanok 	unsigned long flags;
21037931f02SIlya Yanok 
21137931f02SIlya Yanok 	/*
21237931f02SIlya Yanok 	 * We poll because DSPS IP's won't expose several OTG-critical
21337931f02SIlya Yanok 	 * status change events (from the transceiver) otherwise.
21437931f02SIlya Yanok 	 */
21537931f02SIlya Yanok 	devctl = dsps_readb(mregs, MUSB_DEVCTL);
21637931f02SIlya Yanok 	dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
21737931f02SIlya Yanok 				otg_state_string(musb->xceiv->state));
21837931f02SIlya Yanok 
21937931f02SIlya Yanok 	spin_lock_irqsave(&musb->lock, flags);
22037931f02SIlya Yanok 	switch (musb->xceiv->state) {
22137931f02SIlya Yanok 	case OTG_STATE_A_WAIT_BCON:
22237931f02SIlya Yanok 		devctl &= ~MUSB_DEVCTL_SESSION;
22337931f02SIlya Yanok 		dsps_writeb(musb->mregs, MUSB_DEVCTL, devctl);
22437931f02SIlya Yanok 
22537931f02SIlya Yanok 		devctl = dsps_readb(musb->mregs, MUSB_DEVCTL);
22637931f02SIlya Yanok 		if (devctl & MUSB_DEVCTL_BDEVICE) {
22737931f02SIlya Yanok 			musb->xceiv->state = OTG_STATE_B_IDLE;
22837931f02SIlya Yanok 			MUSB_DEV_MODE(musb);
22937931f02SIlya Yanok 		} else {
23037931f02SIlya Yanok 			musb->xceiv->state = OTG_STATE_A_IDLE;
23137931f02SIlya Yanok 			MUSB_HST_MODE(musb);
23237931f02SIlya Yanok 		}
23337931f02SIlya Yanok 		break;
23437931f02SIlya Yanok 	case OTG_STATE_A_WAIT_VFALL:
23537931f02SIlya Yanok 		musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
23637931f02SIlya Yanok 		dsps_writel(musb->ctrl_base, wrp->coreintr_set,
23737931f02SIlya Yanok 			    MUSB_INTR_VBUSERROR << wrp->usb_shift);
23837931f02SIlya Yanok 		break;
23937931f02SIlya Yanok 	case OTG_STATE_B_IDLE:
24037931f02SIlya Yanok 		if (!is_peripheral_enabled(musb))
24137931f02SIlya Yanok 			break;
24237931f02SIlya Yanok 
24337931f02SIlya Yanok 		devctl = dsps_readb(mregs, MUSB_DEVCTL);
24437931f02SIlya Yanok 		if (devctl & MUSB_DEVCTL_BDEVICE)
24537931f02SIlya Yanok 			mod_timer(&glue->timer,
24637931f02SIlya Yanok 					jiffies + wrp->poll_seconds * HZ);
24737931f02SIlya Yanok 		else
24837931f02SIlya Yanok 			musb->xceiv->state = OTG_STATE_A_IDLE;
24937931f02SIlya Yanok 		break;
25037931f02SIlya Yanok 	default:
25137931f02SIlya Yanok 		break;
25237931f02SIlya Yanok 	}
25337931f02SIlya Yanok 	spin_unlock_irqrestore(&musb->lock, flags);
25437931f02SIlya Yanok }
25537931f02SIlya Yanok 
dsps_musb_try_idle(struct musb * musb,unsigned long timeout)25637931f02SIlya Yanok static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
25737931f02SIlya Yanok {
25837931f02SIlya Yanok 	struct device *dev = musb->controller;
25937931f02SIlya Yanok 	struct platform_device *pdev = to_platform_device(dev->parent);
26037931f02SIlya Yanok 	struct dsps_glue *glue = platform_get_drvdata(pdev);
26137931f02SIlya Yanok 	static unsigned long last_timer;
26237931f02SIlya Yanok 
26337931f02SIlya Yanok 	if (!is_otg_enabled(musb))
26437931f02SIlya Yanok 		return;
26537931f02SIlya Yanok 
26637931f02SIlya Yanok 	if (timeout == 0)
26737931f02SIlya Yanok 		timeout = jiffies + msecs_to_jiffies(3);
26837931f02SIlya Yanok 
26937931f02SIlya Yanok 	/* Never idle if active, or when VBUS timeout is not set as host */
27037931f02SIlya Yanok 	if (musb->is_active || (musb->a_wait_bcon == 0 &&
27137931f02SIlya Yanok 				musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
27237931f02SIlya Yanok 		dev_dbg(musb->controller, "%s active, deleting timer\n",
27337931f02SIlya Yanok 				otg_state_string(musb->xceiv->state));
27437931f02SIlya Yanok 		del_timer(&glue->timer);
27537931f02SIlya Yanok 		last_timer = jiffies;
27637931f02SIlya Yanok 		return;
27737931f02SIlya Yanok 	}
27837931f02SIlya Yanok 
27937931f02SIlya Yanok 	if (time_after(last_timer, timeout) && timer_pending(&glue->timer)) {
28037931f02SIlya Yanok 		dev_dbg(musb->controller,
28137931f02SIlya Yanok 			"Longer idle timer already pending, ignoring...\n");
28237931f02SIlya Yanok 		return;
28337931f02SIlya Yanok 	}
28437931f02SIlya Yanok 	last_timer = timeout;
28537931f02SIlya Yanok 
28637931f02SIlya Yanok 	dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
28737931f02SIlya Yanok 		otg_state_string(musb->xceiv->state),
28837931f02SIlya Yanok 			jiffies_to_msecs(timeout - jiffies));
28937931f02SIlya Yanok 	mod_timer(&glue->timer, timeout);
29037931f02SIlya Yanok }
29137931f02SIlya Yanok #endif
29237931f02SIlya Yanok 
dsps_interrupt(int irq,void * hci)29337931f02SIlya Yanok static irqreturn_t dsps_interrupt(int irq, void *hci)
29437931f02SIlya Yanok {
29537931f02SIlya Yanok 	struct musb  *musb = hci;
29637931f02SIlya Yanok 	void __iomem *reg_base = musb->ctrl_base;
29737931f02SIlya Yanok #ifndef __UBOOT__
29837931f02SIlya Yanok 	struct device *dev = musb->controller;
29937931f02SIlya Yanok 	struct platform_device *pdev = to_platform_device(dev->parent);
30037931f02SIlya Yanok 	struct dsps_glue *glue = platform_get_drvdata(pdev);
30137931f02SIlya Yanok 	const struct dsps_musb_wrapper *wrp = glue->wrp;
30237931f02SIlya Yanok #else
30337931f02SIlya Yanok 	const struct dsps_musb_wrapper *wrp = &ti81xx_driver_data;
30437931f02SIlya Yanok #endif
30537931f02SIlya Yanok 	unsigned long flags;
30637931f02SIlya Yanok 	irqreturn_t ret = IRQ_NONE;
30737931f02SIlya Yanok 	u32 epintr, usbintr;
30837931f02SIlya Yanok 
30937931f02SIlya Yanok 	spin_lock_irqsave(&musb->lock, flags);
31037931f02SIlya Yanok 
31137931f02SIlya Yanok 	/* Get endpoint interrupts */
31237931f02SIlya Yanok 	epintr = dsps_readl(reg_base, wrp->epintr_status);
31337931f02SIlya Yanok 	musb->int_rx = (epintr & wrp->rxep_bitmap) >> wrp->rxep_shift;
31437931f02SIlya Yanok 	musb->int_tx = (epintr & wrp->txep_bitmap) >> wrp->txep_shift;
31537931f02SIlya Yanok 
31637931f02SIlya Yanok 	if (epintr)
31737931f02SIlya Yanok 		dsps_writel(reg_base, wrp->epintr_status, epintr);
31837931f02SIlya Yanok 
31937931f02SIlya Yanok 	/* Get usb core interrupts */
32037931f02SIlya Yanok 	usbintr = dsps_readl(reg_base, wrp->coreintr_status);
32137931f02SIlya Yanok 	if (!usbintr && !epintr)
32237931f02SIlya Yanok 		goto eoi;
32337931f02SIlya Yanok 
32437931f02SIlya Yanok 	musb->int_usb =	(usbintr & wrp->usb_bitmap) >> wrp->usb_shift;
32537931f02SIlya Yanok 	if (usbintr)
32637931f02SIlya Yanok 		dsps_writel(reg_base, wrp->coreintr_status, usbintr);
32737931f02SIlya Yanok 
32837931f02SIlya Yanok 	dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n",
32937931f02SIlya Yanok 			usbintr, epintr);
33037931f02SIlya Yanok #ifndef __UBOOT__
33137931f02SIlya Yanok 	/*
33237931f02SIlya Yanok 	 * DRVVBUS IRQs are the only proxy we have (a very poor one!) for
33337931f02SIlya Yanok 	 * DSPS IP's missing ID change IRQ.  We need an ID change IRQ to
33437931f02SIlya Yanok 	 * switch appropriately between halves of the OTG state machine.
33537931f02SIlya Yanok 	 * Managing DEVCTL.SESSION per Mentor docs requires that we know its
33637931f02SIlya Yanok 	 * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
33737931f02SIlya Yanok 	 * Also, DRVVBUS pulses for SRP (but not at 5V) ...
33837931f02SIlya Yanok 	 */
33937931f02SIlya Yanok 	if ((usbintr & MUSB_INTR_BABBLE) && is_host_enabled(musb))
34037931f02SIlya Yanok 		pr_info("CAUTION: musb: Babble Interrupt Occured\n");
34137931f02SIlya Yanok 
34237931f02SIlya Yanok 	if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) {
34337931f02SIlya Yanok 		int drvvbus = dsps_readl(reg_base, wrp->status);
34437931f02SIlya Yanok 		void __iomem *mregs = musb->mregs;
34537931f02SIlya Yanok 		u8 devctl = dsps_readb(mregs, MUSB_DEVCTL);
34637931f02SIlya Yanok 		int err;
34737931f02SIlya Yanok 
34837931f02SIlya Yanok 		err = is_host_enabled(musb) && (musb->int_usb &
34937931f02SIlya Yanok 						MUSB_INTR_VBUSERROR);
35037931f02SIlya Yanok 		if (err) {
35137931f02SIlya Yanok 			/*
35237931f02SIlya Yanok 			 * The Mentor core doesn't debounce VBUS as needed
35337931f02SIlya Yanok 			 * to cope with device connect current spikes. This
35437931f02SIlya Yanok 			 * means it's not uncommon for bus-powered devices
35537931f02SIlya Yanok 			 * to get VBUS errors during enumeration.
35637931f02SIlya Yanok 			 *
35737931f02SIlya Yanok 			 * This is a workaround, but newer RTL from Mentor
35837931f02SIlya Yanok 			 * seems to allow a better one: "re"-starting sessions
35937931f02SIlya Yanok 			 * without waiting for VBUS to stop registering in
36037931f02SIlya Yanok 			 * devctl.
36137931f02SIlya Yanok 			 */
36237931f02SIlya Yanok 			musb->int_usb &= ~MUSB_INTR_VBUSERROR;
36337931f02SIlya Yanok 			musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
36437931f02SIlya Yanok 			mod_timer(&glue->timer,
36537931f02SIlya Yanok 					jiffies + wrp->poll_seconds * HZ);
36637931f02SIlya Yanok 			WARNING("VBUS error workaround (delay coming)\n");
36737931f02SIlya Yanok 		} else if (is_host_enabled(musb) && drvvbus) {
36837931f02SIlya Yanok 			musb->is_active = 1;
36937931f02SIlya Yanok 			MUSB_HST_MODE(musb);
37037931f02SIlya Yanok 			musb->xceiv->otg->default_a = 1;
37137931f02SIlya Yanok 			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
37237931f02SIlya Yanok 			del_timer(&glue->timer);
37337931f02SIlya Yanok 		} else {
37437931f02SIlya Yanok 			musb->is_active = 0;
37537931f02SIlya Yanok 			MUSB_DEV_MODE(musb);
37637931f02SIlya Yanok 			musb->xceiv->otg->default_a = 0;
37737931f02SIlya Yanok 			musb->xceiv->state = OTG_STATE_B_IDLE;
37837931f02SIlya Yanok 		}
37937931f02SIlya Yanok 
38037931f02SIlya Yanok 		/* NOTE: this must complete power-on within 100 ms. */
38137931f02SIlya Yanok 		dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
38237931f02SIlya Yanok 				drvvbus ? "on" : "off",
38337931f02SIlya Yanok 				otg_state_string(musb->xceiv->state),
38437931f02SIlya Yanok 				err ? " ERROR" : "",
38537931f02SIlya Yanok 				devctl);
38637931f02SIlya Yanok 		ret = IRQ_HANDLED;
38737931f02SIlya Yanok 	}
38837931f02SIlya Yanok #endif
38937931f02SIlya Yanok 
39037931f02SIlya Yanok 	if (musb->int_tx || musb->int_rx || musb->int_usb)
39137931f02SIlya Yanok 		ret |= musb_interrupt(musb);
39237931f02SIlya Yanok 
39337931f02SIlya Yanok  eoi:
39437931f02SIlya Yanok 	/* EOI needs to be written for the IRQ to be re-asserted. */
39537931f02SIlya Yanok 	if (ret == IRQ_HANDLED || epintr || usbintr)
39637931f02SIlya Yanok 		dsps_writel(reg_base, wrp->eoi, 1);
39737931f02SIlya Yanok 
39837931f02SIlya Yanok #ifndef __UBOOT__
39937931f02SIlya Yanok 	/* Poll for ID change */
40037931f02SIlya Yanok 	if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE)
40137931f02SIlya Yanok 		mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
40237931f02SIlya Yanok #endif
40337931f02SIlya Yanok 
40437931f02SIlya Yanok 	spin_unlock_irqrestore(&musb->lock, flags);
40537931f02SIlya Yanok 
40637931f02SIlya Yanok 	return ret;
40737931f02SIlya Yanok }
40837931f02SIlya Yanok 
dsps_musb_init(struct musb * musb)40937931f02SIlya Yanok static int dsps_musb_init(struct musb *musb)
41037931f02SIlya Yanok {
41137931f02SIlya Yanok #ifndef __UBOOT__
41237931f02SIlya Yanok 	struct device *dev = musb->controller;
41337931f02SIlya Yanok 	struct musb_hdrc_platform_data *plat = dev->platform_data;
41437931f02SIlya Yanok 	struct platform_device *pdev = to_platform_device(dev->parent);
41537931f02SIlya Yanok 	struct dsps_glue *glue = platform_get_drvdata(pdev);
41637931f02SIlya Yanok 	const struct dsps_musb_wrapper *wrp = glue->wrp;
41737931f02SIlya Yanok 	struct omap_musb_board_data *data = plat->board_data;
41837931f02SIlya Yanok #else
41937931f02SIlya Yanok 	struct omap_musb_board_data *data =
42037931f02SIlya Yanok 			(struct omap_musb_board_data *)musb->controller;
42137931f02SIlya Yanok 	const struct dsps_musb_wrapper *wrp = &ti81xx_driver_data;
42237931f02SIlya Yanok #endif
42337931f02SIlya Yanok 	void __iomem *reg_base = musb->ctrl_base;
42437931f02SIlya Yanok 	u32 rev, val;
42537931f02SIlya Yanok 	int status;
42637931f02SIlya Yanok 
42737931f02SIlya Yanok 	/* mentor core register starts at offset of 0x400 from musb base */
42837931f02SIlya Yanok 	musb->mregs += wrp->musb_core_offset;
42937931f02SIlya Yanok 
43037931f02SIlya Yanok #ifndef __UBOOT__
43137931f02SIlya Yanok 	/* NOP driver needs change if supporting dual instance */
43237931f02SIlya Yanok 	usb_nop_xceiv_register();
43337931f02SIlya Yanok 	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
43437931f02SIlya Yanok 	if (IS_ERR_OR_NULL(musb->xceiv))
43537931f02SIlya Yanok 		return -ENODEV;
43637931f02SIlya Yanok #endif
43737931f02SIlya Yanok 
43837931f02SIlya Yanok 	/* Returns zero if e.g. not clocked */
43937931f02SIlya Yanok 	rev = dsps_readl(reg_base, wrp->revision);
44037931f02SIlya Yanok 	if (!rev) {
44137931f02SIlya Yanok 		status = -ENODEV;
44237931f02SIlya Yanok 		goto err0;
44337931f02SIlya Yanok 	}
44437931f02SIlya Yanok 
44537931f02SIlya Yanok #ifndef __UBOOT__
44637931f02SIlya Yanok 	if (is_host_enabled(musb))
44737931f02SIlya Yanok 		setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
44837931f02SIlya Yanok #endif
44937931f02SIlya Yanok 
45037931f02SIlya Yanok 	/* Reset the musb */
45137931f02SIlya Yanok 	dsps_writel(reg_base, wrp->control, (1 << wrp->reset));
45237931f02SIlya Yanok 
45337931f02SIlya Yanok 	/* Start the on-chip PHY and its PLL. */
45437931f02SIlya Yanok 	if (data->set_phy_power)
455*1cac34ceSMugunthan V N 		data->set_phy_power(data->dev, 1);
45637931f02SIlya Yanok 
45737931f02SIlya Yanok 	musb->isr = dsps_interrupt;
45837931f02SIlya Yanok 
45937931f02SIlya Yanok 	/* reset the otgdisable bit, needed for host mode to work */
46037931f02SIlya Yanok 	val = dsps_readl(reg_base, wrp->phy_utmi);
46137931f02SIlya Yanok 	val &= ~(1 << wrp->otg_disable);
46237931f02SIlya Yanok 	dsps_writel(musb->ctrl_base, wrp->phy_utmi, val);
46337931f02SIlya Yanok 
46437931f02SIlya Yanok 	/* clear level interrupt */
46537931f02SIlya Yanok 	dsps_writel(reg_base, wrp->eoi, 0);
46637931f02SIlya Yanok 
46737931f02SIlya Yanok 	return 0;
46837931f02SIlya Yanok err0:
46937931f02SIlya Yanok #ifndef __UBOOT__
47037931f02SIlya Yanok 	usb_put_phy(musb->xceiv);
47137931f02SIlya Yanok 	usb_nop_xceiv_unregister();
47237931f02SIlya Yanok #endif
47337931f02SIlya Yanok 	return status;
47437931f02SIlya Yanok }
47537931f02SIlya Yanok 
dsps_musb_exit(struct musb * musb)47637931f02SIlya Yanok static int dsps_musb_exit(struct musb *musb)
47737931f02SIlya Yanok {
47837931f02SIlya Yanok #ifndef __UBOOT__
47937931f02SIlya Yanok 	struct device *dev = musb->controller;
48037931f02SIlya Yanok 	struct musb_hdrc_platform_data *plat = dev->platform_data;
48137931f02SIlya Yanok 	struct omap_musb_board_data *data = plat->board_data;
48237931f02SIlya Yanok 	struct platform_device *pdev = to_platform_device(dev->parent);
48337931f02SIlya Yanok 	struct dsps_glue *glue = platform_get_drvdata(pdev);
48437931f02SIlya Yanok #else
48537931f02SIlya Yanok 	struct omap_musb_board_data *data =
48637931f02SIlya Yanok 			(struct omap_musb_board_data *)musb->controller;
48737931f02SIlya Yanok #endif
48837931f02SIlya Yanok 
48937931f02SIlya Yanok #ifndef __UBOOT__
49037931f02SIlya Yanok 	if (is_host_enabled(musb))
49137931f02SIlya Yanok 		del_timer_sync(&glue->timer);
49237931f02SIlya Yanok #endif
49337931f02SIlya Yanok 
49437931f02SIlya Yanok 	/* Shutdown the on-chip PHY and its PLL. */
49537931f02SIlya Yanok 	if (data->set_phy_power)
496*1cac34ceSMugunthan V N 		data->set_phy_power(data->dev, 0);
49737931f02SIlya Yanok 
49837931f02SIlya Yanok #ifndef __UBOOT__
49937931f02SIlya Yanok 	/* NOP driver needs change if supporting dual instance */
50037931f02SIlya Yanok 	usb_put_phy(musb->xceiv);
50137931f02SIlya Yanok 	usb_nop_xceiv_unregister();
50237931f02SIlya Yanok #endif
50337931f02SIlya Yanok 
50437931f02SIlya Yanok 	return 0;
50537931f02SIlya Yanok }
50637931f02SIlya Yanok 
50737931f02SIlya Yanok #ifndef __UBOOT__
50837931f02SIlya Yanok static struct musb_platform_ops dsps_ops = {
50937931f02SIlya Yanok #else
51037931f02SIlya Yanok struct musb_platform_ops musb_dsps_ops = {
51137931f02SIlya Yanok #endif
51237931f02SIlya Yanok 	.init		= dsps_musb_init,
51337931f02SIlya Yanok 	.exit		= dsps_musb_exit,
51437931f02SIlya Yanok 
51537931f02SIlya Yanok 	.enable		= dsps_musb_enable,
51637931f02SIlya Yanok 	.disable	= dsps_musb_disable,
51737931f02SIlya Yanok 
51837931f02SIlya Yanok #ifndef __UBOOT__
51937931f02SIlya Yanok 	.try_idle	= dsps_musb_try_idle,
52037931f02SIlya Yanok #endif
52137931f02SIlya Yanok };
52237931f02SIlya Yanok 
52337931f02SIlya Yanok #ifndef __UBOOT__
52437931f02SIlya Yanok static u64 musb_dmamask = DMA_BIT_MASK(32);
52537931f02SIlya Yanok #endif
52637931f02SIlya Yanok 
52737931f02SIlya Yanok #ifndef __UBOOT__
dsps_create_musb_pdev(struct dsps_glue * glue,u8 id)52837931f02SIlya Yanok static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
52937931f02SIlya Yanok {
53037931f02SIlya Yanok 	struct device *dev = glue->dev;
53137931f02SIlya Yanok 	struct platform_device *pdev = to_platform_device(dev);
53237931f02SIlya Yanok 	struct musb_hdrc_platform_data  *pdata = dev->platform_data;
53337931f02SIlya Yanok 	struct platform_device	*musb;
53437931f02SIlya Yanok 	struct resource *res;
53537931f02SIlya Yanok 	struct resource	resources[2];
53637931f02SIlya Yanok 	char res_name[10];
53737931f02SIlya Yanok 	int ret;
53837931f02SIlya Yanok 
53937931f02SIlya Yanok 	/* get memory resource */
54037931f02SIlya Yanok 	sprintf(res_name, "musb%d", id);
54137931f02SIlya Yanok 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name);
54237931f02SIlya Yanok 	if (!res) {
54337931f02SIlya Yanok 		dev_err(dev, "%s get mem resource failed\n", res_name);
54437931f02SIlya Yanok 		ret = -ENODEV;
54537931f02SIlya Yanok 		goto err0;
54637931f02SIlya Yanok 	}
54737931f02SIlya Yanok 	res->parent = NULL;
54837931f02SIlya Yanok 	resources[0] = *res;
54937931f02SIlya Yanok 
55037931f02SIlya Yanok 	/* get irq resource */
55137931f02SIlya Yanok 	sprintf(res_name, "musb%d-irq", id);
55237931f02SIlya Yanok 	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name);
55337931f02SIlya Yanok 	if (!res) {
55437931f02SIlya Yanok 		dev_err(dev, "%s get irq resource failed\n", res_name);
55537931f02SIlya Yanok 		ret = -ENODEV;
55637931f02SIlya Yanok 		goto err0;
55737931f02SIlya Yanok 	}
55837931f02SIlya Yanok 	res->parent = NULL;
55937931f02SIlya Yanok 	resources[1] = *res;
56037931f02SIlya Yanok 	resources[1].name = "mc";
56137931f02SIlya Yanok 
56237931f02SIlya Yanok 	/* allocate the child platform device */
56337931f02SIlya Yanok 	musb = platform_device_alloc("musb-hdrc", -1);
56437931f02SIlya Yanok 	if (!musb) {
56537931f02SIlya Yanok 		dev_err(dev, "failed to allocate musb device\n");
56637931f02SIlya Yanok 		ret = -ENOMEM;
56737931f02SIlya Yanok 		goto err0;
56837931f02SIlya Yanok 	}
56937931f02SIlya Yanok 
57037931f02SIlya Yanok 	musb->dev.parent		= dev;
57137931f02SIlya Yanok 	musb->dev.dma_mask		= &musb_dmamask;
57237931f02SIlya Yanok 	musb->dev.coherent_dma_mask	= musb_dmamask;
57337931f02SIlya Yanok 
57437931f02SIlya Yanok 	glue->musb			= musb;
57537931f02SIlya Yanok 
57637931f02SIlya Yanok 	pdata->platform_ops		= &dsps_ops;
57737931f02SIlya Yanok 
57837931f02SIlya Yanok 	ret = platform_device_add_resources(musb, resources, 2);
57937931f02SIlya Yanok 	if (ret) {
58037931f02SIlya Yanok 		dev_err(dev, "failed to add resources\n");
58137931f02SIlya Yanok 		goto err1;
58237931f02SIlya Yanok 	}
58337931f02SIlya Yanok 
58437931f02SIlya Yanok 	ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
58537931f02SIlya Yanok 	if (ret) {
58637931f02SIlya Yanok 		dev_err(dev, "failed to add platform_data\n");
58737931f02SIlya Yanok 		goto err1;
58837931f02SIlya Yanok 	}
58937931f02SIlya Yanok 
59037931f02SIlya Yanok 	ret = platform_device_add(musb);
59137931f02SIlya Yanok 	if (ret) {
59237931f02SIlya Yanok 		dev_err(dev, "failed to register musb device\n");
59337931f02SIlya Yanok 		goto err1;
59437931f02SIlya Yanok 	}
59537931f02SIlya Yanok 
59637931f02SIlya Yanok 	return 0;
59737931f02SIlya Yanok 
59837931f02SIlya Yanok err1:
59937931f02SIlya Yanok 	platform_device_put(musb);
60037931f02SIlya Yanok err0:
60137931f02SIlya Yanok 	return ret;
60237931f02SIlya Yanok }
60337931f02SIlya Yanok 
dsps_delete_musb_pdev(struct dsps_glue * glue)60437931f02SIlya Yanok static void __devexit dsps_delete_musb_pdev(struct dsps_glue *glue)
60537931f02SIlya Yanok {
60637931f02SIlya Yanok 	platform_device_del(glue->musb);
60737931f02SIlya Yanok 	platform_device_put(glue->musb);
60837931f02SIlya Yanok }
60937931f02SIlya Yanok 
dsps_probe(struct platform_device * pdev)61037931f02SIlya Yanok static int __devinit dsps_probe(struct platform_device *pdev)
61137931f02SIlya Yanok {
61237931f02SIlya Yanok 	const struct platform_device_id *id = platform_get_device_id(pdev);
61337931f02SIlya Yanok 	const struct dsps_musb_wrapper *wrp =
61437931f02SIlya Yanok 				(struct dsps_musb_wrapper *)id->driver_data;
61537931f02SIlya Yanok 	struct dsps_glue *glue;
61637931f02SIlya Yanok 	struct resource *iomem;
61737931f02SIlya Yanok 	int ret;
61837931f02SIlya Yanok 
61937931f02SIlya Yanok 	/* allocate glue */
62037931f02SIlya Yanok 	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
62137931f02SIlya Yanok 	if (!glue) {
62237931f02SIlya Yanok 		dev_err(&pdev->dev, "unable to allocate glue memory\n");
62337931f02SIlya Yanok 		ret = -ENOMEM;
62437931f02SIlya Yanok 		goto err0;
62537931f02SIlya Yanok 	}
62637931f02SIlya Yanok 
62737931f02SIlya Yanok 	/* get memory resource */
62837931f02SIlya Yanok 	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
62937931f02SIlya Yanok 	if (!iomem) {
63062a3b7ddSRobert P. J. Day 		dev_err(&pdev->dev, "failed to get usbss mem resource\n");
63137931f02SIlya Yanok 		ret = -ENODEV;
63237931f02SIlya Yanok 		goto err1;
63337931f02SIlya Yanok 	}
63437931f02SIlya Yanok 
63537931f02SIlya Yanok 	glue->dev = &pdev->dev;
63637931f02SIlya Yanok 
63737931f02SIlya Yanok 	glue->wrp = kmemdup(wrp, sizeof(*wrp), GFP_KERNEL);
63837931f02SIlya Yanok 	if (!glue->wrp) {
63937931f02SIlya Yanok 		dev_err(&pdev->dev, "failed to duplicate wrapper struct memory\n");
64037931f02SIlya Yanok 		ret = -ENOMEM;
64137931f02SIlya Yanok 		goto err1;
64237931f02SIlya Yanok 	}
64337931f02SIlya Yanok 	platform_set_drvdata(pdev, glue);
64437931f02SIlya Yanok 
64537931f02SIlya Yanok 	/* enable the usbss clocks */
64637931f02SIlya Yanok 	pm_runtime_enable(&pdev->dev);
64737931f02SIlya Yanok 
64837931f02SIlya Yanok 	ret = pm_runtime_get_sync(&pdev->dev);
64937931f02SIlya Yanok 	if (ret < 0) {
65037931f02SIlya Yanok 		dev_err(&pdev->dev, "pm_runtime_get_sync FAILED");
65137931f02SIlya Yanok 		goto err2;
65237931f02SIlya Yanok 	}
65337931f02SIlya Yanok 
65437931f02SIlya Yanok 	/* create the child platform device for first instances of musb */
65537931f02SIlya Yanok 	ret = dsps_create_musb_pdev(glue, 0);
65637931f02SIlya Yanok 	if (ret != 0) {
65737931f02SIlya Yanok 		dev_err(&pdev->dev, "failed to create child pdev\n");
65837931f02SIlya Yanok 		goto err3;
65937931f02SIlya Yanok 	}
66037931f02SIlya Yanok 
66137931f02SIlya Yanok 	return 0;
66237931f02SIlya Yanok 
66337931f02SIlya Yanok err3:
66437931f02SIlya Yanok 	pm_runtime_put(&pdev->dev);
66537931f02SIlya Yanok err2:
66637931f02SIlya Yanok 	pm_runtime_disable(&pdev->dev);
66737931f02SIlya Yanok 	kfree(glue->wrp);
66837931f02SIlya Yanok err1:
66937931f02SIlya Yanok 	kfree(glue);
67037931f02SIlya Yanok err0:
67137931f02SIlya Yanok 	return ret;
67237931f02SIlya Yanok }
dsps_remove(struct platform_device * pdev)67337931f02SIlya Yanok static int __devexit dsps_remove(struct platform_device *pdev)
67437931f02SIlya Yanok {
67537931f02SIlya Yanok 	struct dsps_glue *glue = platform_get_drvdata(pdev);
67637931f02SIlya Yanok 
67737931f02SIlya Yanok 	/* delete the child platform device */
67837931f02SIlya Yanok 	dsps_delete_musb_pdev(glue);
67937931f02SIlya Yanok 
68037931f02SIlya Yanok 	/* disable usbss clocks */
68137931f02SIlya Yanok 	pm_runtime_put(&pdev->dev);
68237931f02SIlya Yanok 	pm_runtime_disable(&pdev->dev);
68337931f02SIlya Yanok 	kfree(glue->wrp);
68437931f02SIlya Yanok 	kfree(glue);
68537931f02SIlya Yanok 	return 0;
68637931f02SIlya Yanok }
68737931f02SIlya Yanok 
68837931f02SIlya Yanok #ifdef CONFIG_PM_SLEEP
dsps_suspend(struct device * dev)68937931f02SIlya Yanok static int dsps_suspend(struct device *dev)
69037931f02SIlya Yanok {
69137931f02SIlya Yanok 	struct musb_hdrc_platform_data *plat = dev->platform_data;
69237931f02SIlya Yanok 	struct omap_musb_board_data *data = plat->board_data;
69337931f02SIlya Yanok 
69437931f02SIlya Yanok 	/* Shutdown the on-chip PHY and its PLL. */
69537931f02SIlya Yanok 	if (data->set_phy_power)
696*1cac34ceSMugunthan V N 		data->set_phy_power(data->dev, 0);
69737931f02SIlya Yanok 
69837931f02SIlya Yanok 	return 0;
69937931f02SIlya Yanok }
70037931f02SIlya Yanok 
dsps_resume(struct device * dev)70137931f02SIlya Yanok static int dsps_resume(struct device *dev)
70237931f02SIlya Yanok {
70337931f02SIlya Yanok 	struct musb_hdrc_platform_data *plat = dev->platform_data;
70437931f02SIlya Yanok 	struct omap_musb_board_data *data = plat->board_data;
70537931f02SIlya Yanok 
70637931f02SIlya Yanok 	/* Start the on-chip PHY and its PLL. */
70737931f02SIlya Yanok 	if (data->set_phy_power)
708*1cac34ceSMugunthan V N 		data->set_phy_power(data->dev, 1);
70937931f02SIlya Yanok 
71037931f02SIlya Yanok 	return 0;
71137931f02SIlya Yanok }
71237931f02SIlya Yanok #endif
71337931f02SIlya Yanok 
71437931f02SIlya Yanok static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume);
71537931f02SIlya Yanok #endif
71637931f02SIlya Yanok 
71737931f02SIlya Yanok #ifndef __UBOOT__
71837931f02SIlya Yanok static const struct platform_device_id musb_dsps_id_table[] __devinitconst = {
71937931f02SIlya Yanok 	{
72037931f02SIlya Yanok 		.name	= "musb-ti81xx",
72137931f02SIlya Yanok 		.driver_data	= (kernel_ulong_t) &ti81xx_driver_data,
72237931f02SIlya Yanok 	},
72337931f02SIlya Yanok 	{  },	/* Terminating Entry */
72437931f02SIlya Yanok };
72537931f02SIlya Yanok MODULE_DEVICE_TABLE(platform, musb_dsps_id_table);
72637931f02SIlya Yanok 
72737931f02SIlya Yanok static const struct of_device_id musb_dsps_of_match[] __devinitconst = {
72837931f02SIlya Yanok 	{ .compatible = "musb-ti81xx", },
72937931f02SIlya Yanok 	{ .compatible = "ti,ti81xx-musb", },
73037931f02SIlya Yanok 	{ .compatible = "ti,am335x-musb", },
73137931f02SIlya Yanok 	{  },
73237931f02SIlya Yanok };
73337931f02SIlya Yanok MODULE_DEVICE_TABLE(of, musb_dsps_of_match);
73437931f02SIlya Yanok 
73537931f02SIlya Yanok static struct platform_driver dsps_usbss_driver = {
73637931f02SIlya Yanok 	.probe		= dsps_probe,
73737931f02SIlya Yanok 	.remove         = __devexit_p(dsps_remove),
73837931f02SIlya Yanok 	.driver         = {
73937931f02SIlya Yanok 		.name   = "musb-dsps",
74037931f02SIlya Yanok 		.pm	= &dsps_pm_ops,
74137931f02SIlya Yanok 		.of_match_table	= musb_dsps_of_match,
74237931f02SIlya Yanok 	},
74337931f02SIlya Yanok 	.id_table	= musb_dsps_id_table,
74437931f02SIlya Yanok };
74537931f02SIlya Yanok 
74637931f02SIlya Yanok MODULE_DESCRIPTION("TI DSPS MUSB Glue Layer");
74737931f02SIlya Yanok MODULE_AUTHOR("Ravi B <ravibabu@ti.com>");
74837931f02SIlya Yanok MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>");
74937931f02SIlya Yanok MODULE_LICENSE("GPL v2");
75037931f02SIlya Yanok 
dsps_init(void)75137931f02SIlya Yanok static int __init dsps_init(void)
75237931f02SIlya Yanok {
75337931f02SIlya Yanok 	return platform_driver_register(&dsps_usbss_driver);
75437931f02SIlya Yanok }
75537931f02SIlya Yanok subsys_initcall(dsps_init);
75637931f02SIlya Yanok 
dsps_exit(void)75737931f02SIlya Yanok static void __exit dsps_exit(void)
75837931f02SIlya Yanok {
75937931f02SIlya Yanok 	platform_driver_unregister(&dsps_usbss_driver);
76037931f02SIlya Yanok }
76137931f02SIlya Yanok module_exit(dsps_exit);
76237931f02SIlya Yanok #endif
763