xref: /openbmc/linux/drivers/usb/musb/ux500.c (revision 8a77f05a)
14bc36fd3SMian Yousaf Kaukab /*
24bc36fd3SMian Yousaf Kaukab  * Copyright (C) 2010 ST-Ericsson AB
34bc36fd3SMian Yousaf Kaukab  * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
44bc36fd3SMian Yousaf Kaukab  *
54bc36fd3SMian Yousaf Kaukab  * Based on omap2430.c
64bc36fd3SMian Yousaf Kaukab  *
74bc36fd3SMian Yousaf Kaukab  * This program is free software; you can redistribute it and/or modify
84bc36fd3SMian Yousaf Kaukab  * it under the terms of the GNU General Public License as published by
94bc36fd3SMian Yousaf Kaukab  * the Free Software Foundation; either version 2 of the License, or
104bc36fd3SMian Yousaf Kaukab  * (at your option) any later version.
114bc36fd3SMian Yousaf Kaukab  *
124bc36fd3SMian Yousaf Kaukab  * This program is distributed in the hope that it will be useful,
134bc36fd3SMian Yousaf Kaukab  * but WITHOUT ANY WARRANTY; without even the implied warranty of
144bc36fd3SMian Yousaf Kaukab  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
154bc36fd3SMian Yousaf Kaukab  * GNU General Public License for more details.
164bc36fd3SMian Yousaf Kaukab  *
174bc36fd3SMian Yousaf Kaukab  * You should have received a copy of the GNU General Public License
184bc36fd3SMian Yousaf Kaukab  * along with this program; if not, write to the Free Software
194bc36fd3SMian Yousaf Kaukab  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
204bc36fd3SMian Yousaf Kaukab  */
214bc36fd3SMian Yousaf Kaukab 
224bc36fd3SMian Yousaf Kaukab #include <linux/module.h>
234bc36fd3SMian Yousaf Kaukab #include <linux/kernel.h>
244bc36fd3SMian Yousaf Kaukab #include <linux/clk.h>
25ded017eeSKishon Vijay Abraham I #include <linux/err.h>
264bc36fd3SMian Yousaf Kaukab #include <linux/io.h>
27313bdb11SLee Jones #include <linux/of.h>
284bc36fd3SMian Yousaf Kaukab #include <linux/platform_device.h>
29af6882beSFabio Baltieri #include <linux/usb/musb-ux500.h>
304bc36fd3SMian Yousaf Kaukab 
314bc36fd3SMian Yousaf Kaukab #include "musb_core.h"
324bc36fd3SMian Yousaf Kaukab 
33a20b1b79SLee Jones static struct musb_hdrc_config ux500_musb_hdrc_config = {
34a20b1b79SLee Jones 	.multipoint	= true,
35a20b1b79SLee Jones 	.dyn_fifo	= true,
36a20b1b79SLee Jones 	.num_eps	= 16,
37a20b1b79SLee Jones 	.ram_bits	= 16,
38a20b1b79SLee Jones };
39a20b1b79SLee Jones 
404bc36fd3SMian Yousaf Kaukab struct ux500_glue {
414bc36fd3SMian Yousaf Kaukab 	struct device		*dev;
424bc36fd3SMian Yousaf Kaukab 	struct platform_device	*musb;
434bc36fd3SMian Yousaf Kaukab 	struct clk		*clk;
444bc36fd3SMian Yousaf Kaukab };
454bc36fd3SMian Yousaf Kaukab #define glue_to_musb(g)	platform_get_drvdata(g->musb)
464bc36fd3SMian Yousaf Kaukab 
47996a9d26SFabio Baltieri static void ux500_musb_set_vbus(struct musb *musb, int is_on)
48996a9d26SFabio Baltieri {
49996a9d26SFabio Baltieri 	u8            devctl;
50996a9d26SFabio Baltieri 	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
51996a9d26SFabio Baltieri 	/* HDRC controls CPEN, but beware current surges during device
52996a9d26SFabio Baltieri 	 * connect.  They can trigger transient overcurrent conditions
53996a9d26SFabio Baltieri 	 * that must be ignored.
54996a9d26SFabio Baltieri 	 */
55996a9d26SFabio Baltieri 
56996a9d26SFabio Baltieri 	devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
57996a9d26SFabio Baltieri 
58996a9d26SFabio Baltieri 	if (is_on) {
59e47d9254SAntoine Tenart 		if (musb->xceiv->otg->state == OTG_STATE_A_IDLE) {
60996a9d26SFabio Baltieri 			/* start the session */
61996a9d26SFabio Baltieri 			devctl |= MUSB_DEVCTL_SESSION;
62996a9d26SFabio Baltieri 			musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
63996a9d26SFabio Baltieri 			/*
64996a9d26SFabio Baltieri 			 * Wait for the musb to set as A device to enable the
65996a9d26SFabio Baltieri 			 * VBUS
66996a9d26SFabio Baltieri 			 */
67996a9d26SFabio Baltieri 			while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {
68996a9d26SFabio Baltieri 
69996a9d26SFabio Baltieri 				if (time_after(jiffies, timeout)) {
70996a9d26SFabio Baltieri 					dev_err(musb->controller,
71996a9d26SFabio Baltieri 					"configured as A device timeout");
72996a9d26SFabio Baltieri 					break;
73996a9d26SFabio Baltieri 				}
74996a9d26SFabio Baltieri 			}
75996a9d26SFabio Baltieri 
76996a9d26SFabio Baltieri 		} else {
77996a9d26SFabio Baltieri 			musb->is_active = 1;
78996a9d26SFabio Baltieri 			musb->xceiv->otg->default_a = 1;
79e47d9254SAntoine Tenart 			musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
80996a9d26SFabio Baltieri 			devctl |= MUSB_DEVCTL_SESSION;
81996a9d26SFabio Baltieri 			MUSB_HST_MODE(musb);
82996a9d26SFabio Baltieri 		}
83996a9d26SFabio Baltieri 	} else {
84996a9d26SFabio Baltieri 		musb->is_active = 0;
85996a9d26SFabio Baltieri 
86996a9d26SFabio Baltieri 		/* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and jumping
87996a9d26SFabio Baltieri 		 * right to B_IDLE...
88996a9d26SFabio Baltieri 		 */
89996a9d26SFabio Baltieri 		musb->xceiv->otg->default_a = 0;
90996a9d26SFabio Baltieri 		devctl &= ~MUSB_DEVCTL_SESSION;
91996a9d26SFabio Baltieri 		MUSB_DEV_MODE(musb);
92996a9d26SFabio Baltieri 	}
93996a9d26SFabio Baltieri 	musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
94996a9d26SFabio Baltieri 
95996a9d26SFabio Baltieri 	/*
96996a9d26SFabio Baltieri 	 * Devctl values will be updated after vbus goes below
97996a9d26SFabio Baltieri 	 * session_valid. The time taken depends on the capacitance
98996a9d26SFabio Baltieri 	 * on VBUS line. The max discharge time can be upto 1 sec
99996a9d26SFabio Baltieri 	 * as per the spec. Typically on our platform, it is 200ms
100996a9d26SFabio Baltieri 	 */
101996a9d26SFabio Baltieri 	if (!is_on)
102996a9d26SFabio Baltieri 		mdelay(200);
103996a9d26SFabio Baltieri 
104996a9d26SFabio Baltieri 	dev_dbg(musb->controller, "VBUS %s, devctl %02x\n",
105e47d9254SAntoine Tenart 		usb_otg_state_string(musb->xceiv->otg->state),
106996a9d26SFabio Baltieri 		musb_readb(musb->mregs, MUSB_DEVCTL));
107996a9d26SFabio Baltieri }
108996a9d26SFabio Baltieri 
1090135522cSFabio Baltieri static int musb_otg_notifications(struct notifier_block *nb,
1100135522cSFabio Baltieri 		unsigned long event, void *unused)
1110135522cSFabio Baltieri {
1120135522cSFabio Baltieri 	struct musb *musb = container_of(nb, struct musb, nb);
1130135522cSFabio Baltieri 
1140135522cSFabio Baltieri 	dev_dbg(musb->controller, "musb_otg_notifications %ld %s\n",
115e47d9254SAntoine Tenart 			event, usb_otg_state_string(musb->xceiv->otg->state));
1160135522cSFabio Baltieri 
1170135522cSFabio Baltieri 	switch (event) {
118af6882beSFabio Baltieri 	case UX500_MUSB_ID:
1190135522cSFabio Baltieri 		dev_dbg(musb->controller, "ID GND\n");
1200135522cSFabio Baltieri 		ux500_musb_set_vbus(musb, 1);
1210135522cSFabio Baltieri 		break;
122af6882beSFabio Baltieri 	case UX500_MUSB_VBUS:
1230135522cSFabio Baltieri 		dev_dbg(musb->controller, "VBUS Connect\n");
1240135522cSFabio Baltieri 		break;
125af6882beSFabio Baltieri 	case UX500_MUSB_NONE:
1260135522cSFabio Baltieri 		dev_dbg(musb->controller, "VBUS Disconnect\n");
1270135522cSFabio Baltieri 		if (is_host_active(musb))
1280135522cSFabio Baltieri 			ux500_musb_set_vbus(musb, 0);
1290135522cSFabio Baltieri 		else
130e47d9254SAntoine Tenart 			musb->xceiv->otg->state = OTG_STATE_B_IDLE;
1310135522cSFabio Baltieri 		break;
1320135522cSFabio Baltieri 	default:
1330135522cSFabio Baltieri 		dev_dbg(musb->controller, "ID float\n");
1340135522cSFabio Baltieri 		return NOTIFY_DONE;
1350135522cSFabio Baltieri 	}
1360135522cSFabio Baltieri 	return NOTIFY_OK;
1370135522cSFabio Baltieri }
1380135522cSFabio Baltieri 
139baef653aSPhilippe De Swert static irqreturn_t ux500_musb_interrupt(int irq, void *__hci)
140baef653aSPhilippe De Swert {
141baef653aSPhilippe De Swert 	unsigned long   flags;
142baef653aSPhilippe De Swert 	irqreturn_t     retval = IRQ_NONE;
143baef653aSPhilippe De Swert 	struct musb     *musb = __hci;
144baef653aSPhilippe De Swert 
145baef653aSPhilippe De Swert 	spin_lock_irqsave(&musb->lock, flags);
146baef653aSPhilippe De Swert 
147baef653aSPhilippe De Swert 	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
148baef653aSPhilippe De Swert 	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
149baef653aSPhilippe De Swert 	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
150baef653aSPhilippe De Swert 
151baef653aSPhilippe De Swert 	if (musb->int_usb || musb->int_tx || musb->int_rx)
152baef653aSPhilippe De Swert 		retval = musb_interrupt(musb);
153baef653aSPhilippe De Swert 
154baef653aSPhilippe De Swert 	spin_unlock_irqrestore(&musb->lock, flags);
155baef653aSPhilippe De Swert 
156baef653aSPhilippe De Swert 	return retval;
157baef653aSPhilippe De Swert }
158baef653aSPhilippe De Swert 
1594bc36fd3SMian Yousaf Kaukab static int ux500_musb_init(struct musb *musb)
1604bc36fd3SMian Yousaf Kaukab {
1610135522cSFabio Baltieri 	int status;
1620135522cSFabio Baltieri 
163662dca54SKishon Vijay Abraham I 	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
164ded017eeSKishon Vijay Abraham I 	if (IS_ERR_OR_NULL(musb->xceiv)) {
1654bc36fd3SMian Yousaf Kaukab 		pr_err("HS USB OTG: no transceiver configured\n");
16625736e0cSMing Lei 		return -EPROBE_DEFER;
1674bc36fd3SMian Yousaf Kaukab 	}
1684bc36fd3SMian Yousaf Kaukab 
1690135522cSFabio Baltieri 	musb->nb.notifier_call = musb_otg_notifications;
1700135522cSFabio Baltieri 	status = usb_register_notifier(musb->xceiv, &musb->nb);
1710135522cSFabio Baltieri 	if (status < 0) {
1720135522cSFabio Baltieri 		dev_dbg(musb->controller, "notification register failed\n");
1730135522cSFabio Baltieri 		return status;
1740135522cSFabio Baltieri 	}
1750135522cSFabio Baltieri 
176baef653aSPhilippe De Swert 	musb->isr = ux500_musb_interrupt;
177baef653aSPhilippe De Swert 
1784bc36fd3SMian Yousaf Kaukab 	return 0;
1794bc36fd3SMian Yousaf Kaukab }
1804bc36fd3SMian Yousaf Kaukab 
1814bc36fd3SMian Yousaf Kaukab static int ux500_musb_exit(struct musb *musb)
1824bc36fd3SMian Yousaf Kaukab {
1830135522cSFabio Baltieri 	usb_unregister_notifier(musb->xceiv, &musb->nb);
1840135522cSFabio Baltieri 
185721002ecSKishon Vijay Abraham I 	usb_put_phy(musb->xceiv);
1864bc36fd3SMian Yousaf Kaukab 
1874bc36fd3SMian Yousaf Kaukab 	return 0;
1884bc36fd3SMian Yousaf Kaukab }
1894bc36fd3SMian Yousaf Kaukab 
1904bc36fd3SMian Yousaf Kaukab static const struct musb_platform_ops ux500_ops = {
191d026e9c7STony Lindgren 	.quirks		= MUSB_INDEXED_EP,
1924bc36fd3SMian Yousaf Kaukab 	.init		= ux500_musb_init,
1934bc36fd3SMian Yousaf Kaukab 	.exit		= ux500_musb_exit,
1948a77f05aSTony Lindgren 	.fifo_mode	= 5,
195996a9d26SFabio Baltieri 
196996a9d26SFabio Baltieri 	.set_vbus	= ux500_musb_set_vbus,
1974bc36fd3SMian Yousaf Kaukab };
1984bc36fd3SMian Yousaf Kaukab 
199313bdb11SLee Jones static struct musb_hdrc_platform_data *
200313bdb11SLee Jones ux500_of_probe(struct platform_device *pdev, struct device_node *np)
201313bdb11SLee Jones {
202313bdb11SLee Jones 	struct musb_hdrc_platform_data *pdata;
203313bdb11SLee Jones 	const char *mode;
204313bdb11SLee Jones 	int strlen;
205313bdb11SLee Jones 
206313bdb11SLee Jones 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
207313bdb11SLee Jones 	if (!pdata)
208313bdb11SLee Jones 		return NULL;
209313bdb11SLee Jones 
210313bdb11SLee Jones 	mode = of_get_property(np, "dr_mode", &strlen);
211313bdb11SLee Jones 	if (!mode) {
212313bdb11SLee Jones 		dev_err(&pdev->dev, "No 'dr_mode' property found\n");
213313bdb11SLee Jones 		return NULL;
214313bdb11SLee Jones 	}
215313bdb11SLee Jones 
216313bdb11SLee Jones 	if (strlen > 0) {
217313bdb11SLee Jones 		if (!strcmp(mode, "host"))
218313bdb11SLee Jones 			pdata->mode = MUSB_HOST;
219313bdb11SLee Jones 		if (!strcmp(mode, "otg"))
220313bdb11SLee Jones 			pdata->mode = MUSB_OTG;
221313bdb11SLee Jones 		if (!strcmp(mode, "peripheral"))
222313bdb11SLee Jones 			pdata->mode = MUSB_PERIPHERAL;
223313bdb11SLee Jones 	}
224313bdb11SLee Jones 
225313bdb11SLee Jones 	return pdata;
226313bdb11SLee Jones }
227313bdb11SLee Jones 
22841ac7b3aSBill Pemberton static int ux500_probe(struct platform_device *pdev)
2294bc36fd3SMian Yousaf Kaukab {
23009fc7d22SFelipe Balbi 	struct resource musb_resources[2];
231c1a7d67cSJingoo Han 	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev);
232313bdb11SLee Jones 	struct device_node		*np = pdev->dev.of_node;
2334bc36fd3SMian Yousaf Kaukab 	struct platform_device		*musb;
2344bc36fd3SMian Yousaf Kaukab 	struct ux500_glue		*glue;
2354bc36fd3SMian Yousaf Kaukab 	struct clk			*clk;
2364bc36fd3SMian Yousaf Kaukab 	int				ret = -ENOMEM;
2374bc36fd3SMian Yousaf Kaukab 
238313bdb11SLee Jones 	if (!pdata) {
239313bdb11SLee Jones 		if (np) {
240313bdb11SLee Jones 			pdata = ux500_of_probe(pdev, np);
241313bdb11SLee Jones 			if (!pdata)
242313bdb11SLee Jones 				goto err0;
243313bdb11SLee Jones 
244313bdb11SLee Jones 			pdev->dev.platform_data = pdata;
245313bdb11SLee Jones 		} else {
246313bdb11SLee Jones 			dev_err(&pdev->dev, "no pdata or device tree found\n");
247313bdb11SLee Jones 			goto err0;
248313bdb11SLee Jones 		}
249313bdb11SLee Jones 	}
250313bdb11SLee Jones 
251d7dc5bdeSHimangi Saraogi 	glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
25224c611b9SPeter Chen 	if (!glue)
2534bc36fd3SMian Yousaf Kaukab 		goto err0;
2544bc36fd3SMian Yousaf Kaukab 
2552f771164SSebastian Andrzej Siewior 	musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
2564bc36fd3SMian Yousaf Kaukab 	if (!musb) {
2574bc36fd3SMian Yousaf Kaukab 		dev_err(&pdev->dev, "failed to allocate musb device\n");
258d7dc5bdeSHimangi Saraogi 		goto err0;
2594bc36fd3SMian Yousaf Kaukab 	}
2604bc36fd3SMian Yousaf Kaukab 
261d7dc5bdeSHimangi Saraogi 	clk = devm_clk_get(&pdev->dev, NULL);
2624bc36fd3SMian Yousaf Kaukab 	if (IS_ERR(clk)) {
2634bc36fd3SMian Yousaf Kaukab 		dev_err(&pdev->dev, "failed to get clock\n");
2644bc36fd3SMian Yousaf Kaukab 		ret = PTR_ERR(clk);
265d7dc5bdeSHimangi Saraogi 		goto err1;
2664bc36fd3SMian Yousaf Kaukab 	}
2674bc36fd3SMian Yousaf Kaukab 
26899d17cfaSFabio Baltieri 	ret = clk_prepare_enable(clk);
2694bc36fd3SMian Yousaf Kaukab 	if (ret) {
2704bc36fd3SMian Yousaf Kaukab 		dev_err(&pdev->dev, "failed to enable clock\n");
271d7dc5bdeSHimangi Saraogi 		goto err1;
2724bc36fd3SMian Yousaf Kaukab 	}
2734bc36fd3SMian Yousaf Kaukab 
2744bc36fd3SMian Yousaf Kaukab 	musb->dev.parent		= &pdev->dev;
2751e6eebb4SLee Jones 	musb->dev.dma_mask		= &pdev->dev.coherent_dma_mask;
27687266064SMian Yousaf Kaukab 	musb->dev.coherent_dma_mask	= pdev->dev.coherent_dma_mask;
2774bc36fd3SMian Yousaf Kaukab 
2784bc36fd3SMian Yousaf Kaukab 	glue->dev			= &pdev->dev;
2794bc36fd3SMian Yousaf Kaukab 	glue->musb			= musb;
2804bc36fd3SMian Yousaf Kaukab 	glue->clk			= clk;
2814bc36fd3SMian Yousaf Kaukab 
2824bc36fd3SMian Yousaf Kaukab 	pdata->platform_ops		= &ux500_ops;
283a20b1b79SLee Jones 	pdata->config 			= &ux500_musb_hdrc_config;
2844bc36fd3SMian Yousaf Kaukab 
2854bc36fd3SMian Yousaf Kaukab 	platform_set_drvdata(pdev, glue);
2864bc36fd3SMian Yousaf Kaukab 
28709fc7d22SFelipe Balbi 	memset(musb_resources, 0x00, sizeof(*musb_resources) *
28809fc7d22SFelipe Balbi 			ARRAY_SIZE(musb_resources));
28909fc7d22SFelipe Balbi 
29009fc7d22SFelipe Balbi 	musb_resources[0].name = pdev->resource[0].name;
29109fc7d22SFelipe Balbi 	musb_resources[0].start = pdev->resource[0].start;
29209fc7d22SFelipe Balbi 	musb_resources[0].end = pdev->resource[0].end;
29309fc7d22SFelipe Balbi 	musb_resources[0].flags = pdev->resource[0].flags;
29409fc7d22SFelipe Balbi 
29509fc7d22SFelipe Balbi 	musb_resources[1].name = pdev->resource[1].name;
29609fc7d22SFelipe Balbi 	musb_resources[1].start = pdev->resource[1].start;
29709fc7d22SFelipe Balbi 	musb_resources[1].end = pdev->resource[1].end;
29809fc7d22SFelipe Balbi 	musb_resources[1].flags = pdev->resource[1].flags;
29909fc7d22SFelipe Balbi 
30009fc7d22SFelipe Balbi 	ret = platform_device_add_resources(musb, musb_resources,
30109fc7d22SFelipe Balbi 			ARRAY_SIZE(musb_resources));
3024bc36fd3SMian Yousaf Kaukab 	if (ret) {
3034bc36fd3SMian Yousaf Kaukab 		dev_err(&pdev->dev, "failed to add resources\n");
304d7dc5bdeSHimangi Saraogi 		goto err2;
3054bc36fd3SMian Yousaf Kaukab 	}
3064bc36fd3SMian Yousaf Kaukab 
3074bc36fd3SMian Yousaf Kaukab 	ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
3084bc36fd3SMian Yousaf Kaukab 	if (ret) {
3094bc36fd3SMian Yousaf Kaukab 		dev_err(&pdev->dev, "failed to add platform_data\n");
310d7dc5bdeSHimangi Saraogi 		goto err2;
3114bc36fd3SMian Yousaf Kaukab 	}
3124bc36fd3SMian Yousaf Kaukab 
3134bc36fd3SMian Yousaf Kaukab 	ret = platform_device_add(musb);
3144bc36fd3SMian Yousaf Kaukab 	if (ret) {
3154bc36fd3SMian Yousaf Kaukab 		dev_err(&pdev->dev, "failed to register musb device\n");
316d7dc5bdeSHimangi Saraogi 		goto err2;
3174bc36fd3SMian Yousaf Kaukab 	}
3184bc36fd3SMian Yousaf Kaukab 
3194bc36fd3SMian Yousaf Kaukab 	return 0;
3204bc36fd3SMian Yousaf Kaukab 
321d7dc5bdeSHimangi Saraogi err2:
32299d17cfaSFabio Baltieri 	clk_disable_unprepare(clk);
3234bc36fd3SMian Yousaf Kaukab 
3244bc36fd3SMian Yousaf Kaukab err1:
325d7dc5bdeSHimangi Saraogi 	platform_device_put(musb);
3264bc36fd3SMian Yousaf Kaukab 
3274bc36fd3SMian Yousaf Kaukab err0:
3284bc36fd3SMian Yousaf Kaukab 	return ret;
3294bc36fd3SMian Yousaf Kaukab }
3304bc36fd3SMian Yousaf Kaukab 
331fb4e98abSBill Pemberton static int ux500_remove(struct platform_device *pdev)
3324bc36fd3SMian Yousaf Kaukab {
3334bc36fd3SMian Yousaf Kaukab 	struct ux500_glue	*glue = platform_get_drvdata(pdev);
3344bc36fd3SMian Yousaf Kaukab 
3354b0de6f3SWei Yongjun 	platform_device_unregister(glue->musb);
33699d17cfaSFabio Baltieri 	clk_disable_unprepare(glue->clk);
3374bc36fd3SMian Yousaf Kaukab 
3384bc36fd3SMian Yousaf Kaukab 	return 0;
3394bc36fd3SMian Yousaf Kaukab }
3404bc36fd3SMian Yousaf Kaukab 
3414bc36fd3SMian Yousaf Kaukab #ifdef CONFIG_PM
3424bc36fd3SMian Yousaf Kaukab static int ux500_suspend(struct device *dev)
3434bc36fd3SMian Yousaf Kaukab {
3444bc36fd3SMian Yousaf Kaukab 	struct ux500_glue	*glue = dev_get_drvdata(dev);
3454bc36fd3SMian Yousaf Kaukab 	struct musb		*musb = glue_to_musb(glue);
3464bc36fd3SMian Yousaf Kaukab 
347b96d3b08SHeikki Krogerus 	usb_phy_set_suspend(musb->xceiv, 1);
34899d17cfaSFabio Baltieri 	clk_disable_unprepare(glue->clk);
3494bc36fd3SMian Yousaf Kaukab 
3504bc36fd3SMian Yousaf Kaukab 	return 0;
3514bc36fd3SMian Yousaf Kaukab }
3524bc36fd3SMian Yousaf Kaukab 
3534bc36fd3SMian Yousaf Kaukab static int ux500_resume(struct device *dev)
3544bc36fd3SMian Yousaf Kaukab {
3554bc36fd3SMian Yousaf Kaukab 	struct ux500_glue	*glue = dev_get_drvdata(dev);
3564bc36fd3SMian Yousaf Kaukab 	struct musb		*musb = glue_to_musb(glue);
3574bc36fd3SMian Yousaf Kaukab 	int			ret;
3584bc36fd3SMian Yousaf Kaukab 
35999d17cfaSFabio Baltieri 	ret = clk_prepare_enable(glue->clk);
3604bc36fd3SMian Yousaf Kaukab 	if (ret) {
3614bc36fd3SMian Yousaf Kaukab 		dev_err(dev, "failed to enable clock\n");
3624bc36fd3SMian Yousaf Kaukab 		return ret;
3634bc36fd3SMian Yousaf Kaukab 	}
3644bc36fd3SMian Yousaf Kaukab 
365b96d3b08SHeikki Krogerus 	usb_phy_set_suspend(musb->xceiv, 0);
3664bc36fd3SMian Yousaf Kaukab 
3674bc36fd3SMian Yousaf Kaukab 	return 0;
3684bc36fd3SMian Yousaf Kaukab }
3694bc36fd3SMian Yousaf Kaukab #endif
3704bc36fd3SMian Yousaf Kaukab 
371a89adb09SDaniel Mack static SIMPLE_DEV_PM_OPS(ux500_pm_ops, ux500_suspend, ux500_resume);
372a89adb09SDaniel Mack 
373313bdb11SLee Jones static const struct of_device_id ux500_match[] = {
374313bdb11SLee Jones         { .compatible = "stericsson,db8500-musb", },
375313bdb11SLee Jones         {}
376313bdb11SLee Jones };
377313bdb11SLee Jones 
3784bc36fd3SMian Yousaf Kaukab static struct platform_driver ux500_driver = {
379e9e8c85eSFelipe Balbi 	.probe		= ux500_probe,
3807690417dSBill Pemberton 	.remove		= ux500_remove,
3814bc36fd3SMian Yousaf Kaukab 	.driver		= {
3824bc36fd3SMian Yousaf Kaukab 		.name	= "musb-ux500",
383a89adb09SDaniel Mack 		.pm	= &ux500_pm_ops,
384313bdb11SLee Jones 		.of_match_table = ux500_match,
3854bc36fd3SMian Yousaf Kaukab 	},
3864bc36fd3SMian Yousaf Kaukab };
3874bc36fd3SMian Yousaf Kaukab 
3884bc36fd3SMian Yousaf Kaukab MODULE_DESCRIPTION("UX500 MUSB Glue Layer");
3894bc36fd3SMian Yousaf Kaukab MODULE_AUTHOR("Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>");
3904bc36fd3SMian Yousaf Kaukab MODULE_LICENSE("GPL v2");
3910e7090a6SSrinivas Kandagatla module_platform_driver(ux500_driver);
392