xref: /openbmc/linux/drivers/usb/musb/ux500.c (revision 5fd54ace)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
24bc36fd3SMian Yousaf Kaukab /*
34bc36fd3SMian Yousaf Kaukab  * Copyright (C) 2010 ST-Ericsson AB
44bc36fd3SMian Yousaf Kaukab  * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
54bc36fd3SMian Yousaf Kaukab  *
64bc36fd3SMian Yousaf Kaukab  * Based on omap2430.c
74bc36fd3SMian Yousaf Kaukab  *
84bc36fd3SMian Yousaf Kaukab  * This program is free software; you can redistribute it and/or modify
94bc36fd3SMian Yousaf Kaukab  * it under the terms of the GNU General Public License as published by
104bc36fd3SMian Yousaf Kaukab  * the Free Software Foundation; either version 2 of the License, or
114bc36fd3SMian Yousaf Kaukab  * (at your option) any later version.
124bc36fd3SMian Yousaf Kaukab  *
134bc36fd3SMian Yousaf Kaukab  * This program is distributed in the hope that it will be useful,
144bc36fd3SMian Yousaf Kaukab  * but WITHOUT ANY WARRANTY; without even the implied warranty of
154bc36fd3SMian Yousaf Kaukab  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
164bc36fd3SMian Yousaf Kaukab  * GNU General Public License for more details.
174bc36fd3SMian Yousaf Kaukab  *
184bc36fd3SMian Yousaf Kaukab  * You should have received a copy of the GNU General Public License
194bc36fd3SMian Yousaf Kaukab  * along with this program; if not, write to the Free Software
204bc36fd3SMian Yousaf Kaukab  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
214bc36fd3SMian Yousaf Kaukab  */
224bc36fd3SMian Yousaf Kaukab 
234bc36fd3SMian Yousaf Kaukab #include <linux/module.h>
244bc36fd3SMian Yousaf Kaukab #include <linux/kernel.h>
254bc36fd3SMian Yousaf Kaukab #include <linux/clk.h>
26ded017eeSKishon Vijay Abraham I #include <linux/err.h>
274bc36fd3SMian Yousaf Kaukab #include <linux/io.h>
28313bdb11SLee Jones #include <linux/of.h>
294bc36fd3SMian Yousaf Kaukab #include <linux/platform_device.h>
30af6882beSFabio Baltieri #include <linux/usb/musb-ux500.h>
314bc36fd3SMian Yousaf Kaukab 
324bc36fd3SMian Yousaf Kaukab #include "musb_core.h"
334bc36fd3SMian Yousaf Kaukab 
341e572aa5SBhumika Goyal static const struct musb_hdrc_config ux500_musb_hdrc_config = {
35a20b1b79SLee Jones 	.multipoint	= true,
36a20b1b79SLee Jones 	.dyn_fifo	= true,
37a20b1b79SLee Jones 	.num_eps	= 16,
38a20b1b79SLee Jones 	.ram_bits	= 16,
39a20b1b79SLee Jones };
40a20b1b79SLee Jones 
414bc36fd3SMian Yousaf Kaukab struct ux500_glue {
424bc36fd3SMian Yousaf Kaukab 	struct device		*dev;
434bc36fd3SMian Yousaf Kaukab 	struct platform_device	*musb;
444bc36fd3SMian Yousaf Kaukab 	struct clk		*clk;
454bc36fd3SMian Yousaf Kaukab };
464bc36fd3SMian Yousaf Kaukab #define glue_to_musb(g)	platform_get_drvdata(g->musb)
474bc36fd3SMian Yousaf Kaukab 
48996a9d26SFabio Baltieri static void ux500_musb_set_vbus(struct musb *musb, int is_on)
49996a9d26SFabio Baltieri {
50996a9d26SFabio Baltieri 	u8            devctl;
51996a9d26SFabio Baltieri 	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
52996a9d26SFabio Baltieri 	/* HDRC controls CPEN, but beware current surges during device
53996a9d26SFabio Baltieri 	 * connect.  They can trigger transient overcurrent conditions
54996a9d26SFabio Baltieri 	 * that must be ignored.
55996a9d26SFabio Baltieri 	 */
56996a9d26SFabio Baltieri 
57996a9d26SFabio Baltieri 	devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
58996a9d26SFabio Baltieri 
59996a9d26SFabio Baltieri 	if (is_on) {
60e47d9254SAntoine Tenart 		if (musb->xceiv->otg->state == OTG_STATE_A_IDLE) {
61996a9d26SFabio Baltieri 			/* start the session */
62996a9d26SFabio Baltieri 			devctl |= MUSB_DEVCTL_SESSION;
63996a9d26SFabio Baltieri 			musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
64996a9d26SFabio Baltieri 			/*
65996a9d26SFabio Baltieri 			 * Wait for the musb to set as A device to enable the
66996a9d26SFabio Baltieri 			 * VBUS
67996a9d26SFabio Baltieri 			 */
68996a9d26SFabio Baltieri 			while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {
69996a9d26SFabio Baltieri 
70996a9d26SFabio Baltieri 				if (time_after(jiffies, timeout)) {
71996a9d26SFabio Baltieri 					dev_err(musb->controller,
72996a9d26SFabio Baltieri 					"configured as A device timeout");
73996a9d26SFabio Baltieri 					break;
74996a9d26SFabio Baltieri 				}
75996a9d26SFabio Baltieri 			}
76996a9d26SFabio Baltieri 
77996a9d26SFabio Baltieri 		} else {
78996a9d26SFabio Baltieri 			musb->is_active = 1;
79996a9d26SFabio Baltieri 			musb->xceiv->otg->default_a = 1;
80e47d9254SAntoine Tenart 			musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
81996a9d26SFabio Baltieri 			devctl |= MUSB_DEVCTL_SESSION;
82996a9d26SFabio Baltieri 			MUSB_HST_MODE(musb);
83996a9d26SFabio Baltieri 		}
84996a9d26SFabio Baltieri 	} else {
85996a9d26SFabio Baltieri 		musb->is_active = 0;
86996a9d26SFabio Baltieri 
87996a9d26SFabio Baltieri 		/* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and jumping
88996a9d26SFabio Baltieri 		 * right to B_IDLE...
89996a9d26SFabio Baltieri 		 */
90996a9d26SFabio Baltieri 		musb->xceiv->otg->default_a = 0;
91996a9d26SFabio Baltieri 		devctl &= ~MUSB_DEVCTL_SESSION;
92996a9d26SFabio Baltieri 		MUSB_DEV_MODE(musb);
93996a9d26SFabio Baltieri 	}
94996a9d26SFabio Baltieri 	musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
95996a9d26SFabio Baltieri 
96996a9d26SFabio Baltieri 	/*
97996a9d26SFabio Baltieri 	 * Devctl values will be updated after vbus goes below
98996a9d26SFabio Baltieri 	 * session_valid. The time taken depends on the capacitance
99996a9d26SFabio Baltieri 	 * on VBUS line. The max discharge time can be upto 1 sec
100996a9d26SFabio Baltieri 	 * as per the spec. Typically on our platform, it is 200ms
101996a9d26SFabio Baltieri 	 */
102996a9d26SFabio Baltieri 	if (!is_on)
103996a9d26SFabio Baltieri 		mdelay(200);
104996a9d26SFabio Baltieri 
105996a9d26SFabio Baltieri 	dev_dbg(musb->controller, "VBUS %s, devctl %02x\n",
106e47d9254SAntoine Tenart 		usb_otg_state_string(musb->xceiv->otg->state),
107996a9d26SFabio Baltieri 		musb_readb(musb->mregs, MUSB_DEVCTL));
108996a9d26SFabio Baltieri }
109996a9d26SFabio Baltieri 
1100135522cSFabio Baltieri static int musb_otg_notifications(struct notifier_block *nb,
1110135522cSFabio Baltieri 		unsigned long event, void *unused)
1120135522cSFabio Baltieri {
1130135522cSFabio Baltieri 	struct musb *musb = container_of(nb, struct musb, nb);
1140135522cSFabio Baltieri 
1150135522cSFabio Baltieri 	dev_dbg(musb->controller, "musb_otg_notifications %ld %s\n",
116e47d9254SAntoine Tenart 			event, usb_otg_state_string(musb->xceiv->otg->state));
1170135522cSFabio Baltieri 
1180135522cSFabio Baltieri 	switch (event) {
119af6882beSFabio Baltieri 	case UX500_MUSB_ID:
1200135522cSFabio Baltieri 		dev_dbg(musb->controller, "ID GND\n");
1210135522cSFabio Baltieri 		ux500_musb_set_vbus(musb, 1);
1220135522cSFabio Baltieri 		break;
123af6882beSFabio Baltieri 	case UX500_MUSB_VBUS:
1240135522cSFabio Baltieri 		dev_dbg(musb->controller, "VBUS Connect\n");
1250135522cSFabio Baltieri 		break;
126af6882beSFabio Baltieri 	case UX500_MUSB_NONE:
1270135522cSFabio Baltieri 		dev_dbg(musb->controller, "VBUS Disconnect\n");
1280135522cSFabio Baltieri 		if (is_host_active(musb))
1290135522cSFabio Baltieri 			ux500_musb_set_vbus(musb, 0);
1300135522cSFabio Baltieri 		else
131e47d9254SAntoine Tenart 			musb->xceiv->otg->state = OTG_STATE_B_IDLE;
1320135522cSFabio Baltieri 		break;
1330135522cSFabio Baltieri 	default:
1340135522cSFabio Baltieri 		dev_dbg(musb->controller, "ID float\n");
1350135522cSFabio Baltieri 		return NOTIFY_DONE;
1360135522cSFabio Baltieri 	}
1370135522cSFabio Baltieri 	return NOTIFY_OK;
1380135522cSFabio Baltieri }
1390135522cSFabio Baltieri 
140baef653aSPhilippe De Swert static irqreturn_t ux500_musb_interrupt(int irq, void *__hci)
141baef653aSPhilippe De Swert {
142baef653aSPhilippe De Swert 	unsigned long   flags;
143baef653aSPhilippe De Swert 	irqreturn_t     retval = IRQ_NONE;
144baef653aSPhilippe De Swert 	struct musb     *musb = __hci;
145baef653aSPhilippe De Swert 
146baef653aSPhilippe De Swert 	spin_lock_irqsave(&musb->lock, flags);
147baef653aSPhilippe De Swert 
148baef653aSPhilippe De Swert 	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
149baef653aSPhilippe De Swert 	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
150baef653aSPhilippe De Swert 	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
151baef653aSPhilippe De Swert 
152baef653aSPhilippe De Swert 	if (musb->int_usb || musb->int_tx || musb->int_rx)
153baef653aSPhilippe De Swert 		retval = musb_interrupt(musb);
154baef653aSPhilippe De Swert 
155baef653aSPhilippe De Swert 	spin_unlock_irqrestore(&musb->lock, flags);
156baef653aSPhilippe De Swert 
157baef653aSPhilippe De Swert 	return retval;
158baef653aSPhilippe De Swert }
159baef653aSPhilippe De Swert 
1604bc36fd3SMian Yousaf Kaukab static int ux500_musb_init(struct musb *musb)
1614bc36fd3SMian Yousaf Kaukab {
1620135522cSFabio Baltieri 	int status;
1630135522cSFabio Baltieri 
164662dca54SKishon Vijay Abraham I 	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
165ded017eeSKishon Vijay Abraham I 	if (IS_ERR_OR_NULL(musb->xceiv)) {
1664bc36fd3SMian Yousaf Kaukab 		pr_err("HS USB OTG: no transceiver configured\n");
16725736e0cSMing Lei 		return -EPROBE_DEFER;
1684bc36fd3SMian Yousaf Kaukab 	}
1694bc36fd3SMian Yousaf Kaukab 
1700135522cSFabio Baltieri 	musb->nb.notifier_call = musb_otg_notifications;
1710135522cSFabio Baltieri 	status = usb_register_notifier(musb->xceiv, &musb->nb);
1720135522cSFabio Baltieri 	if (status < 0) {
1730135522cSFabio Baltieri 		dev_dbg(musb->controller, "notification register failed\n");
1740135522cSFabio Baltieri 		return status;
1750135522cSFabio Baltieri 	}
1760135522cSFabio Baltieri 
177baef653aSPhilippe De Swert 	musb->isr = ux500_musb_interrupt;
178baef653aSPhilippe De Swert 
1794bc36fd3SMian Yousaf Kaukab 	return 0;
1804bc36fd3SMian Yousaf Kaukab }
1814bc36fd3SMian Yousaf Kaukab 
1824bc36fd3SMian Yousaf Kaukab static int ux500_musb_exit(struct musb *musb)
1834bc36fd3SMian Yousaf Kaukab {
1840135522cSFabio Baltieri 	usb_unregister_notifier(musb->xceiv, &musb->nb);
1850135522cSFabio Baltieri 
186721002ecSKishon Vijay Abraham I 	usb_put_phy(musb->xceiv);
1874bc36fd3SMian Yousaf Kaukab 
1884bc36fd3SMian Yousaf Kaukab 	return 0;
1894bc36fd3SMian Yousaf Kaukab }
1904bc36fd3SMian Yousaf Kaukab 
1914bc36fd3SMian Yousaf Kaukab static const struct musb_platform_ops ux500_ops = {
192f8e9f34fSTony Lindgren 	.quirks		= MUSB_DMA_UX500 | MUSB_INDEXED_EP,
1937f6283edSTony Lindgren #ifdef CONFIG_USB_UX500_DMA
1947f6283edSTony Lindgren 	.dma_init	= ux500_dma_controller_create,
1957f6283edSTony Lindgren 	.dma_exit	= ux500_dma_controller_destroy,
1967f6283edSTony Lindgren #endif
1974bc36fd3SMian Yousaf Kaukab 	.init		= ux500_musb_init,
1984bc36fd3SMian Yousaf Kaukab 	.exit		= ux500_musb_exit,
1998a77f05aSTony Lindgren 	.fifo_mode	= 5,
200996a9d26SFabio Baltieri 
201996a9d26SFabio Baltieri 	.set_vbus	= ux500_musb_set_vbus,
2024bc36fd3SMian Yousaf Kaukab };
2034bc36fd3SMian Yousaf Kaukab 
204313bdb11SLee Jones static struct musb_hdrc_platform_data *
205313bdb11SLee Jones ux500_of_probe(struct platform_device *pdev, struct device_node *np)
206313bdb11SLee Jones {
207313bdb11SLee Jones 	struct musb_hdrc_platform_data *pdata;
208313bdb11SLee Jones 	const char *mode;
209313bdb11SLee Jones 	int strlen;
210313bdb11SLee Jones 
211313bdb11SLee Jones 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
212313bdb11SLee Jones 	if (!pdata)
213313bdb11SLee Jones 		return NULL;
214313bdb11SLee Jones 
215313bdb11SLee Jones 	mode = of_get_property(np, "dr_mode", &strlen);
216313bdb11SLee Jones 	if (!mode) {
217313bdb11SLee Jones 		dev_err(&pdev->dev, "No 'dr_mode' property found\n");
218313bdb11SLee Jones 		return NULL;
219313bdb11SLee Jones 	}
220313bdb11SLee Jones 
221313bdb11SLee Jones 	if (strlen > 0) {
222313bdb11SLee Jones 		if (!strcmp(mode, "host"))
223313bdb11SLee Jones 			pdata->mode = MUSB_HOST;
224313bdb11SLee Jones 		if (!strcmp(mode, "otg"))
225313bdb11SLee Jones 			pdata->mode = MUSB_OTG;
226313bdb11SLee Jones 		if (!strcmp(mode, "peripheral"))
227313bdb11SLee Jones 			pdata->mode = MUSB_PERIPHERAL;
228313bdb11SLee Jones 	}
229313bdb11SLee Jones 
230313bdb11SLee Jones 	return pdata;
231313bdb11SLee Jones }
232313bdb11SLee Jones 
23341ac7b3aSBill Pemberton static int ux500_probe(struct platform_device *pdev)
2344bc36fd3SMian Yousaf Kaukab {
23509fc7d22SFelipe Balbi 	struct resource musb_resources[2];
236c1a7d67cSJingoo Han 	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev);
237313bdb11SLee Jones 	struct device_node		*np = pdev->dev.of_node;
2384bc36fd3SMian Yousaf Kaukab 	struct platform_device		*musb;
2394bc36fd3SMian Yousaf Kaukab 	struct ux500_glue		*glue;
2404bc36fd3SMian Yousaf Kaukab 	struct clk			*clk;
2414bc36fd3SMian Yousaf Kaukab 	int				ret = -ENOMEM;
2424bc36fd3SMian Yousaf Kaukab 
243313bdb11SLee Jones 	if (!pdata) {
244313bdb11SLee Jones 		if (np) {
245313bdb11SLee Jones 			pdata = ux500_of_probe(pdev, np);
246313bdb11SLee Jones 			if (!pdata)
247313bdb11SLee Jones 				goto err0;
248313bdb11SLee Jones 
249313bdb11SLee Jones 			pdev->dev.platform_data = pdata;
250313bdb11SLee Jones 		} else {
251313bdb11SLee Jones 			dev_err(&pdev->dev, "no pdata or device tree found\n");
252313bdb11SLee Jones 			goto err0;
253313bdb11SLee Jones 		}
254313bdb11SLee Jones 	}
255313bdb11SLee Jones 
256d7dc5bdeSHimangi Saraogi 	glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
25724c611b9SPeter Chen 	if (!glue)
2584bc36fd3SMian Yousaf Kaukab 		goto err0;
2594bc36fd3SMian Yousaf Kaukab 
2602f771164SSebastian Andrzej Siewior 	musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
2614bc36fd3SMian Yousaf Kaukab 	if (!musb) {
2624bc36fd3SMian Yousaf Kaukab 		dev_err(&pdev->dev, "failed to allocate musb device\n");
263d7dc5bdeSHimangi Saraogi 		goto err0;
2644bc36fd3SMian Yousaf Kaukab 	}
2654bc36fd3SMian Yousaf Kaukab 
266d7dc5bdeSHimangi Saraogi 	clk = devm_clk_get(&pdev->dev, NULL);
2674bc36fd3SMian Yousaf Kaukab 	if (IS_ERR(clk)) {
2684bc36fd3SMian Yousaf Kaukab 		dev_err(&pdev->dev, "failed to get clock\n");
2694bc36fd3SMian Yousaf Kaukab 		ret = PTR_ERR(clk);
270d7dc5bdeSHimangi Saraogi 		goto err1;
2714bc36fd3SMian Yousaf Kaukab 	}
2724bc36fd3SMian Yousaf Kaukab 
27399d17cfaSFabio Baltieri 	ret = clk_prepare_enable(clk);
2744bc36fd3SMian Yousaf Kaukab 	if (ret) {
2754bc36fd3SMian Yousaf Kaukab 		dev_err(&pdev->dev, "failed to enable clock\n");
276d7dc5bdeSHimangi Saraogi 		goto err1;
2774bc36fd3SMian Yousaf Kaukab 	}
2784bc36fd3SMian Yousaf Kaukab 
2794bc36fd3SMian Yousaf Kaukab 	musb->dev.parent		= &pdev->dev;
2801e6eebb4SLee Jones 	musb->dev.dma_mask		= &pdev->dev.coherent_dma_mask;
28187266064SMian Yousaf Kaukab 	musb->dev.coherent_dma_mask	= pdev->dev.coherent_dma_mask;
2824bc36fd3SMian Yousaf Kaukab 
2834bc36fd3SMian Yousaf Kaukab 	glue->dev			= &pdev->dev;
2844bc36fd3SMian Yousaf Kaukab 	glue->musb			= musb;
2854bc36fd3SMian Yousaf Kaukab 	glue->clk			= clk;
2864bc36fd3SMian Yousaf Kaukab 
2874bc36fd3SMian Yousaf Kaukab 	pdata->platform_ops		= &ux500_ops;
288a20b1b79SLee Jones 	pdata->config 			= &ux500_musb_hdrc_config;
2894bc36fd3SMian Yousaf Kaukab 
2904bc36fd3SMian Yousaf Kaukab 	platform_set_drvdata(pdev, glue);
2914bc36fd3SMian Yousaf Kaukab 
29209fc7d22SFelipe Balbi 	memset(musb_resources, 0x00, sizeof(*musb_resources) *
29309fc7d22SFelipe Balbi 			ARRAY_SIZE(musb_resources));
29409fc7d22SFelipe Balbi 
29509fc7d22SFelipe Balbi 	musb_resources[0].name = pdev->resource[0].name;
29609fc7d22SFelipe Balbi 	musb_resources[0].start = pdev->resource[0].start;
29709fc7d22SFelipe Balbi 	musb_resources[0].end = pdev->resource[0].end;
29809fc7d22SFelipe Balbi 	musb_resources[0].flags = pdev->resource[0].flags;
29909fc7d22SFelipe Balbi 
30009fc7d22SFelipe Balbi 	musb_resources[1].name = pdev->resource[1].name;
30109fc7d22SFelipe Balbi 	musb_resources[1].start = pdev->resource[1].start;
30209fc7d22SFelipe Balbi 	musb_resources[1].end = pdev->resource[1].end;
30309fc7d22SFelipe Balbi 	musb_resources[1].flags = pdev->resource[1].flags;
30409fc7d22SFelipe Balbi 
30509fc7d22SFelipe Balbi 	ret = platform_device_add_resources(musb, musb_resources,
30609fc7d22SFelipe Balbi 			ARRAY_SIZE(musb_resources));
3074bc36fd3SMian Yousaf Kaukab 	if (ret) {
3084bc36fd3SMian Yousaf Kaukab 		dev_err(&pdev->dev, "failed to add resources\n");
309d7dc5bdeSHimangi Saraogi 		goto err2;
3104bc36fd3SMian Yousaf Kaukab 	}
3114bc36fd3SMian Yousaf Kaukab 
3124bc36fd3SMian Yousaf Kaukab 	ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
3134bc36fd3SMian Yousaf Kaukab 	if (ret) {
3144bc36fd3SMian Yousaf Kaukab 		dev_err(&pdev->dev, "failed to add platform_data\n");
315d7dc5bdeSHimangi Saraogi 		goto err2;
3164bc36fd3SMian Yousaf Kaukab 	}
3174bc36fd3SMian Yousaf Kaukab 
3184bc36fd3SMian Yousaf Kaukab 	ret = platform_device_add(musb);
3194bc36fd3SMian Yousaf Kaukab 	if (ret) {
3204bc36fd3SMian Yousaf Kaukab 		dev_err(&pdev->dev, "failed to register musb device\n");
321d7dc5bdeSHimangi Saraogi 		goto err2;
3224bc36fd3SMian Yousaf Kaukab 	}
3234bc36fd3SMian Yousaf Kaukab 
3244bc36fd3SMian Yousaf Kaukab 	return 0;
3254bc36fd3SMian Yousaf Kaukab 
326d7dc5bdeSHimangi Saraogi err2:
32799d17cfaSFabio Baltieri 	clk_disable_unprepare(clk);
3284bc36fd3SMian Yousaf Kaukab 
3294bc36fd3SMian Yousaf Kaukab err1:
330d7dc5bdeSHimangi Saraogi 	platform_device_put(musb);
3314bc36fd3SMian Yousaf Kaukab 
3324bc36fd3SMian Yousaf Kaukab err0:
3334bc36fd3SMian Yousaf Kaukab 	return ret;
3344bc36fd3SMian Yousaf Kaukab }
3354bc36fd3SMian Yousaf Kaukab 
336fb4e98abSBill Pemberton static int ux500_remove(struct platform_device *pdev)
3374bc36fd3SMian Yousaf Kaukab {
3384bc36fd3SMian Yousaf Kaukab 	struct ux500_glue	*glue = platform_get_drvdata(pdev);
3394bc36fd3SMian Yousaf Kaukab 
3404b0de6f3SWei Yongjun 	platform_device_unregister(glue->musb);
34199d17cfaSFabio Baltieri 	clk_disable_unprepare(glue->clk);
3424bc36fd3SMian Yousaf Kaukab 
3434bc36fd3SMian Yousaf Kaukab 	return 0;
3444bc36fd3SMian Yousaf Kaukab }
3454bc36fd3SMian Yousaf Kaukab 
34630d09223SFelipe Balbi #ifdef CONFIG_PM_SLEEP
3474bc36fd3SMian Yousaf Kaukab static int ux500_suspend(struct device *dev)
3484bc36fd3SMian Yousaf Kaukab {
3494bc36fd3SMian Yousaf Kaukab 	struct ux500_glue	*glue = dev_get_drvdata(dev);
3504bc36fd3SMian Yousaf Kaukab 	struct musb		*musb = glue_to_musb(glue);
3514bc36fd3SMian Yousaf Kaukab 
35279c5623fSUlf Hansson 	if (musb)
353b96d3b08SHeikki Krogerus 		usb_phy_set_suspend(musb->xceiv, 1);
35479c5623fSUlf Hansson 
35599d17cfaSFabio Baltieri 	clk_disable_unprepare(glue->clk);
3564bc36fd3SMian Yousaf Kaukab 
3574bc36fd3SMian Yousaf Kaukab 	return 0;
3584bc36fd3SMian Yousaf Kaukab }
3594bc36fd3SMian Yousaf Kaukab 
3604bc36fd3SMian Yousaf Kaukab static int ux500_resume(struct device *dev)
3614bc36fd3SMian Yousaf Kaukab {
3624bc36fd3SMian Yousaf Kaukab 	struct ux500_glue	*glue = dev_get_drvdata(dev);
3634bc36fd3SMian Yousaf Kaukab 	struct musb		*musb = glue_to_musb(glue);
3644bc36fd3SMian Yousaf Kaukab 	int			ret;
3654bc36fd3SMian Yousaf Kaukab 
36699d17cfaSFabio Baltieri 	ret = clk_prepare_enable(glue->clk);
3674bc36fd3SMian Yousaf Kaukab 	if (ret) {
3684bc36fd3SMian Yousaf Kaukab 		dev_err(dev, "failed to enable clock\n");
3694bc36fd3SMian Yousaf Kaukab 		return ret;
3704bc36fd3SMian Yousaf Kaukab 	}
3714bc36fd3SMian Yousaf Kaukab 
37279c5623fSUlf Hansson 	if (musb)
373b96d3b08SHeikki Krogerus 		usb_phy_set_suspend(musb->xceiv, 0);
3744bc36fd3SMian Yousaf Kaukab 
3754bc36fd3SMian Yousaf Kaukab 	return 0;
3764bc36fd3SMian Yousaf Kaukab }
3774bc36fd3SMian Yousaf Kaukab #endif
3784bc36fd3SMian Yousaf Kaukab 
379a89adb09SDaniel Mack static SIMPLE_DEV_PM_OPS(ux500_pm_ops, ux500_suspend, ux500_resume);
380a89adb09SDaniel Mack 
381313bdb11SLee Jones static const struct of_device_id ux500_match[] = {
382313bdb11SLee Jones         { .compatible = "stericsson,db8500-musb", },
383313bdb11SLee Jones         {}
384313bdb11SLee Jones };
385313bdb11SLee Jones 
386523d5dafSLuis de Bethencourt MODULE_DEVICE_TABLE(of, ux500_match);
387523d5dafSLuis de Bethencourt 
3884bc36fd3SMian Yousaf Kaukab static struct platform_driver ux500_driver = {
389e9e8c85eSFelipe Balbi 	.probe		= ux500_probe,
3907690417dSBill Pemberton 	.remove		= ux500_remove,
3914bc36fd3SMian Yousaf Kaukab 	.driver		= {
3924bc36fd3SMian Yousaf Kaukab 		.name	= "musb-ux500",
393a89adb09SDaniel Mack 		.pm	= &ux500_pm_ops,
394313bdb11SLee Jones 		.of_match_table = ux500_match,
3954bc36fd3SMian Yousaf Kaukab 	},
3964bc36fd3SMian Yousaf Kaukab };
3974bc36fd3SMian Yousaf Kaukab 
3984bc36fd3SMian Yousaf Kaukab MODULE_DESCRIPTION("UX500 MUSB Glue Layer");
3994bc36fd3SMian Yousaf Kaukab MODULE_AUTHOR("Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>");
4004bc36fd3SMian Yousaf Kaukab MODULE_LICENSE("GPL v2");
4010e7090a6SSrinivas Kandagatla module_platform_driver(ux500_driver);
402