aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAjay Kumar Gupta <ajay.gupta@ti.com>2010-10-19 03:08:12 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-10-22 13:22:16 -0400
commiteb83092c2b24587719c917a1d6a5b682eeaa03df (patch)
tree6c182a3b1418a13d49c644eaeb7d003e139aa9cb /drivers/usb
parent3a0d30bcdfa73bd865f29899eb4bf29b58c4f54a (diff)
USB: musb: add musb support for AM35x
AM35x has musb interface and uses CPPI4.1 DMA engine. Current patch supports only PIO mode. DMA support can be added later once basic CPPI4.1 DMA patch is accepted. Also added USB_MUSB_AM35X which is required to differentiate musb ips between OMAP3x and AM35x. This config would be used to for below purposes, - Select am35x.c instead of omap2430.c for compilation at drivers/usb/musb directory. Please note there are significant differneces in these two files as musb ip in quite different on AM35x. Please note that in multi omap configuration only omap2430.c file will get compiled and we would require to select only AM35x based board config to compile am35x.c - Select workaround codes applicable for AM35x musb issues. one such workaround is for bytewise read issue on AM35x. Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com> Signed-off-by: Felipe Balbi <balbi@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/musb/Kconfig13
-rw-r--r--drivers/usb/musb/Makefile6
-rw-r--r--drivers/usb/musb/am35x.c494
-rw-r--r--drivers/usb/musb/musb_core.h1
4 files changed, 512 insertions, 2 deletions
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 1dd21c2315e4..341a37a469bd 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -60,6 +60,17 @@ comment "OMAP 44xx high speed USB support"
60comment "Blackfin high speed USB Support" 60comment "Blackfin high speed USB Support"
61 depends on USB_MUSB_HDRC && ((BF54x && !BF544) || (BF52x && !BF522 && !BF523)) 61 depends on USB_MUSB_HDRC && ((BF54x && !BF544) || (BF52x && !BF522 && !BF523))
62 62
63config USB_MUSB_AM35X
64 bool
65 depends on USB_MUSB_HDRC && !ARCH_OMAP2430 && !ARCH_OMAP4
66 select NOP_USB_XCEIV
67 default MACH_OMAP3517EVM
68 help
69 Select this option if your platform is based on AM35x. As
70 AM35x has an updated MUSB with CPPI4.1 DMA so this config
71 is introduced to differentiate musb ip between OMAP3x and
72 AM35x platforms.
73
63config USB_TUSB6010 74config USB_TUSB6010
64 boolean "TUSB 6010 support" 75 boolean "TUSB 6010 support"
65 depends on USB_MUSB_HDRC && !USB_MUSB_SOC 76 depends on USB_MUSB_HDRC && !USB_MUSB_SOC
@@ -147,7 +158,7 @@ config USB_MUSB_HDRC_HCD
147config MUSB_PIO_ONLY 158config MUSB_PIO_ONLY
148 bool 'Disable DMA (always use PIO)' 159 bool 'Disable DMA (always use PIO)'
149 depends on USB_MUSB_HDRC 160 depends on USB_MUSB_HDRC
150 default USB_TUSB6010 || ARCH_DAVINCI_DA8XX 161 default USB_TUSB6010 || ARCH_DAVINCI_DA8XX || USB_MUSB_AM35X
151 help 162 help
152 All data is copied between memory and FIFO by the CPU. 163 All data is copied between memory and FIFO by the CPU.
153 DMA controllers are ignored. 164 DMA controllers are ignored.
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index ffc0e0525823..ce164e8998d8 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -12,7 +12,11 @@ musb_hdrc-$(CONFIG_ARCH_DAVINCI_DMx) += davinci.o
12musb_hdrc-$(CONFIG_ARCH_DAVINCI_DA8XX) += da8xx.o 12musb_hdrc-$(CONFIG_ARCH_DAVINCI_DA8XX) += da8xx.o
13musb_hdrc-$(CONFIG_USB_TUSB6010) += tusb6010.o 13musb_hdrc-$(CONFIG_USB_TUSB6010) += tusb6010.o
14musb_hdrc-$(CONFIG_ARCH_OMAP2430) += omap2430.o 14musb_hdrc-$(CONFIG_ARCH_OMAP2430) += omap2430.o
15musb_hdrc-$(CONFIG_ARCH_OMAP3430) += omap2430.o 15ifeq ($(CONFIG_USB_MUSB_AM35X),y)
16 musb_hdrc-$(CONFIG_ARCH_OMAP3430) += am35x.o
17else
18 musb_hdrc-$(CONFIG_ARCH_OMAP3430) += omap2430.o
19endif
16musb_hdrc-$(CONFIG_ARCH_OMAP4) += omap2430.o 20musb_hdrc-$(CONFIG_ARCH_OMAP4) += omap2430.o
17musb_hdrc-$(CONFIG_BF54x) += blackfin.o 21musb_hdrc-$(CONFIG_BF54x) += blackfin.o
18musb_hdrc-$(CONFIG_BF52x) += blackfin.o 22musb_hdrc-$(CONFIG_BF52x) += blackfin.o
diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c
new file mode 100644
index 000000000000..53962a0389eb
--- /dev/null
+++ b/drivers/usb/musb/am35x.c
@@ -0,0 +1,494 @@
1/*
2 * Texas Instruments AM35x "glue layer"
3 *
4 * Copyright (c) 2010, by Texas Instruments
5 *
6 * Based on the DA8xx "glue layer" code.
7 * Copyright (c) 2008-2009, MontaVista Software, Inc. <source@mvista.com>
8 *
9 * This file is part of the Inventra Controller Driver for Linux.
10 *
11 * The Inventra Controller Driver for Linux is free software; you
12 * can redistribute it and/or modify it under the terms of the GNU
13 * General Public License version 2 as published by the Free Software
14 * Foundation.
15 *
16 * The Inventra Controller Driver for Linux is distributed in
17 * the hope that it will be useful, but WITHOUT ANY WARRANTY;
18 * without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
20 * License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with The Inventra Controller Driver for Linux ; if not,
24 * write to the Free Software Foundation, Inc., 59 Temple Place,
25 * Suite 330, Boston, MA 02111-1307 USA
26 *
27 */
28
29#include <linux/init.h>
30#include <linux/clk.h>
31#include <linux/io.h>
32
33#include <plat/control.h>
34#include <plat/usb.h>
35
36#include "musb_core.h"
37
38/*
39 * AM35x specific definitions
40 */
41/* USB 2.0 OTG module registers */
42#define USB_REVISION_REG 0x00
43#define USB_CTRL_REG 0x04
44#define USB_STAT_REG 0x08
45#define USB_EMULATION_REG 0x0c
46/* 0x10 Reserved */
47#define USB_AUTOREQ_REG 0x14
48#define USB_SRP_FIX_TIME_REG 0x18
49#define USB_TEARDOWN_REG 0x1c
50#define EP_INTR_SRC_REG 0x20
51#define EP_INTR_SRC_SET_REG 0x24
52#define EP_INTR_SRC_CLEAR_REG 0x28
53#define EP_INTR_MASK_REG 0x2c
54#define EP_INTR_MASK_SET_REG 0x30
55#define EP_INTR_MASK_CLEAR_REG 0x34
56#define EP_INTR_SRC_MASKED_REG 0x38
57#define CORE_INTR_SRC_REG 0x40
58#define CORE_INTR_SRC_SET_REG 0x44
59#define CORE_INTR_SRC_CLEAR_REG 0x48
60#define CORE_INTR_MASK_REG 0x4c
61#define CORE_INTR_MASK_SET_REG 0x50
62#define CORE_INTR_MASK_CLEAR_REG 0x54
63#define CORE_INTR_SRC_MASKED_REG 0x58
64/* 0x5c Reserved */
65#define USB_END_OF_INTR_REG 0x60
66
67/* Control register bits */
68#define AM35X_SOFT_RESET_MASK 1
69
70/* USB interrupt register bits */
71#define AM35X_INTR_USB_SHIFT 16
72#define AM35X_INTR_USB_MASK (0x1ff << AM35X_INTR_USB_SHIFT)
73#define AM35X_INTR_DRVVBUS 0x100
74#define AM35X_INTR_RX_SHIFT 16
75#define AM35X_INTR_TX_SHIFT 0
76#define AM35X_TX_EP_MASK 0xffff /* EP0 + 15 Tx EPs */
77#define AM35X_RX_EP_MASK 0xfffe /* 15 Rx EPs */
78#define AM35X_TX_INTR_MASK (AM35X_TX_EP_MASK << AM35X_INTR_TX_SHIFT)
79#define AM35X_RX_INTR_MASK (AM35X_RX_EP_MASK << AM35X_INTR_RX_SHIFT)
80
81#define USB_MENTOR_CORE_OFFSET 0x400
82
83static inline void phy_on(void)
84{
85 unsigned long timeout = jiffies + msecs_to_jiffies(100);
86 u32 devconf2;
87
88 /*
89 * Start the on-chip PHY and its PLL.
90 */
91 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
92
93 devconf2 &= ~(CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN);
94 devconf2 |= CONF2_PHY_PLLON;
95
96 omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
97
98 DBG(1, "Waiting for PHY clock good...\n");
99 while (!(omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2)
100 & CONF2_PHYCLKGD)) {
101 cpu_relax();
102
103 if (time_after(jiffies, timeout)) {
104 DBG(1, "musb PHY clock good timed out\n");
105 break;
106 }
107 }
108}
109
110static inline void phy_off(void)
111{
112 u32 devconf2;
113
114 /*
115 * Power down the on-chip PHY.
116 */
117 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
118
119 devconf2 &= ~CONF2_PHY_PLLON;
120 devconf2 |= CONF2_PHYPWRDN | CONF2_OTGPWRDN;
121 omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
122}
123
124/*
125 * musb_platform_enable - enable interrupts
126 */
127void musb_platform_enable(struct musb *musb)
128{
129 void __iomem *reg_base = musb->ctrl_base;
130 u32 epmask;
131
132 /* Workaround: setup IRQs through both register sets. */
133 epmask = ((musb->epmask & AM35X_TX_EP_MASK) << AM35X_INTR_TX_SHIFT) |
134 ((musb->epmask & AM35X_RX_EP_MASK) << AM35X_INTR_RX_SHIFT);
135
136 musb_writel(reg_base, EP_INTR_MASK_SET_REG, epmask);
137 musb_writel(reg_base, CORE_INTR_MASK_SET_REG, AM35X_INTR_USB_MASK);
138
139 /* Force the DRVVBUS IRQ so we can start polling for ID change. */
140 if (is_otg_enabled(musb))
141 musb_writel(reg_base, CORE_INTR_SRC_SET_REG,
142 AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT);
143}
144
145/*
146 * musb_platform_disable - disable HDRC and flush interrupts
147 */
148void musb_platform_disable(struct musb *musb)
149{
150 void __iomem *reg_base = musb->ctrl_base;
151
152 musb_writel(reg_base, CORE_INTR_MASK_CLEAR_REG, AM35X_INTR_USB_MASK);
153 musb_writel(reg_base, EP_INTR_MASK_CLEAR_REG,
154 AM35X_TX_INTR_MASK | AM35X_RX_INTR_MASK);
155 musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
156 musb_writel(reg_base, USB_END_OF_INTR_REG, 0);
157}
158
159#ifdef CONFIG_USB_MUSB_HDRC_HCD
160#define portstate(stmt) stmt
161#else
162#define portstate(stmt)
163#endif
164
165static void am35x_set_vbus(struct musb *musb, int is_on)
166{
167 WARN_ON(is_on && is_peripheral_active(musb));
168}
169
170#define POLL_SECONDS 2
171
172static struct timer_list otg_workaround;
173
174static void otg_timer(unsigned long _musb)
175{
176 struct musb *musb = (void *)_musb;
177 void __iomem *mregs = musb->mregs;
178 u8 devctl;
179 unsigned long flags;
180
181 /*
182 * We poll because AM35x's won't expose several OTG-critical
183 * status change events (from the transceiver) otherwise.
184 */
185 devctl = musb_readb(mregs, MUSB_DEVCTL);
186 DBG(7, "Poll devctl %02x (%s)\n", devctl, otg_state_string(musb));
187
188 spin_lock_irqsave(&musb->lock, flags);
189 switch (musb->xceiv->state) {
190 case OTG_STATE_A_WAIT_BCON:
191 devctl &= ~MUSB_DEVCTL_SESSION;
192 musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
193
194 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
195 if (devctl & MUSB_DEVCTL_BDEVICE) {
196 musb->xceiv->state = OTG_STATE_B_IDLE;
197 MUSB_DEV_MODE(musb);
198 } else {
199 musb->xceiv->state = OTG_STATE_A_IDLE;
200 MUSB_HST_MODE(musb);
201 }
202 break;
203 case OTG_STATE_A_WAIT_VFALL:
204 musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
205 musb_writel(musb->ctrl_base, CORE_INTR_SRC_SET_REG,
206 MUSB_INTR_VBUSERROR << AM35X_INTR_USB_SHIFT);
207 break;
208 case OTG_STATE_B_IDLE:
209 if (!is_peripheral_enabled(musb))
210 break;
211
212 devctl = musb_readb(mregs, MUSB_DEVCTL);
213 if (devctl & MUSB_DEVCTL_BDEVICE)
214 mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
215 else
216 musb->xceiv->state = OTG_STATE_A_IDLE;
217 break;
218 default:
219 break;
220 }
221 spin_unlock_irqrestore(&musb->lock, flags);
222}
223
224void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
225{
226 static unsigned long last_timer;
227
228 if (!is_otg_enabled(musb))
229 return;
230
231 if (timeout == 0)
232 timeout = jiffies + msecs_to_jiffies(3);
233
234 /* Never idle if active, or when VBUS timeout is not set as host */
235 if (musb->is_active || (musb->a_wait_bcon == 0 &&
236 musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
237 DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
238 del_timer(&otg_workaround);
239 last_timer = jiffies;
240 return;
241 }
242
243 if (time_after(last_timer, timeout) && timer_pending(&otg_workaround)) {
244 DBG(4, "Longer idle timer already pending, ignoring...\n");
245 return;
246 }
247 last_timer = timeout;
248
249 DBG(4, "%s inactive, starting idle timer for %u ms\n",
250 otg_state_string(musb), jiffies_to_msecs(timeout - jiffies));
251 mod_timer(&otg_workaround, timeout);
252}
253
254static irqreturn_t am35x_interrupt(int irq, void *hci)
255{
256 struct musb *musb = hci;
257 void __iomem *reg_base = musb->ctrl_base;
258 unsigned long flags;
259 irqreturn_t ret = IRQ_NONE;
260 u32 epintr, usbintr, lvl_intr;
261
262 spin_lock_irqsave(&musb->lock, flags);
263
264 /* Get endpoint interrupts */
265 epintr = musb_readl(reg_base, EP_INTR_SRC_MASKED_REG);
266
267 if (epintr) {
268 musb_writel(reg_base, EP_INTR_SRC_CLEAR_REG, epintr);
269
270 musb->int_rx =
271 (epintr & AM35X_RX_INTR_MASK) >> AM35X_INTR_RX_SHIFT;
272 musb->int_tx =
273 (epintr & AM35X_TX_INTR_MASK) >> AM35X_INTR_TX_SHIFT;
274 }
275
276 /* Get usb core interrupts */
277 usbintr = musb_readl(reg_base, CORE_INTR_SRC_MASKED_REG);
278 if (!usbintr && !epintr)
279 goto eoi;
280
281 if (usbintr) {
282 musb_writel(reg_base, CORE_INTR_SRC_CLEAR_REG, usbintr);
283
284 musb->int_usb =
285 (usbintr & AM35X_INTR_USB_MASK) >> AM35X_INTR_USB_SHIFT;
286 }
287 /*
288 * DRVVBUS IRQs are the only proxy we have (a very poor one!) for
289 * AM35x's missing ID change IRQ. We need an ID change IRQ to
290 * switch appropriately between halves of the OTG state machine.
291 * Managing DEVCTL.SESSION per Mentor docs requires that we know its
292 * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
293 * Also, DRVVBUS pulses for SRP (but not at 5V) ...
294 */
295 if (usbintr & (AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT)) {
296 int drvvbus = musb_readl(reg_base, USB_STAT_REG);
297 void __iomem *mregs = musb->mregs;
298 u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
299 int err;
300
301 err = is_host_enabled(musb) && (musb->int_usb &
302 MUSB_INTR_VBUSERROR);
303 if (err) {
304 /*
305 * The Mentor core doesn't debounce VBUS as needed
306 * to cope with device connect current spikes. This
307 * means it's not uncommon for bus-powered devices
308 * to get VBUS errors during enumeration.
309 *
310 * This is a workaround, but newer RTL from Mentor
311 * seems to allow a better one: "re"-starting sessions
312 * without waiting for VBUS to stop registering in
313 * devctl.
314 */
315 musb->int_usb &= ~MUSB_INTR_VBUSERROR;
316 musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
317 mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
318 WARNING("VBUS error workaround (delay coming)\n");
319 } else if (is_host_enabled(musb) && drvvbus) {
320 MUSB_HST_MODE(musb);
321 musb->xceiv->default_a = 1;
322 musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
323 portstate(musb->port1_status |= USB_PORT_STAT_POWER);
324 del_timer(&otg_workaround);
325 } else {
326 musb->is_active = 0;
327 MUSB_DEV_MODE(musb);
328 musb->xceiv->default_a = 0;
329 musb->xceiv->state = OTG_STATE_B_IDLE;
330 portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
331 }
332
333 /* NOTE: this must complete power-on within 100 ms. */
334 DBG(2, "VBUS %s (%s)%s, devctl %02x\n",
335 drvvbus ? "on" : "off",
336 otg_state_string(musb),
337 err ? " ERROR" : "",
338 devctl);
339 ret = IRQ_HANDLED;
340 }
341
342 if (musb->int_tx || musb->int_rx || musb->int_usb)
343 ret |= musb_interrupt(musb);
344
345eoi:
346 /* EOI needs to be written for the IRQ to be re-asserted. */
347 if (ret == IRQ_HANDLED || epintr || usbintr) {
348 /* clear level interrupt */
349 lvl_intr = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
350 lvl_intr |= AM35XX_USBOTGSS_INT_CLR;
351 omap_ctrl_writel(lvl_intr, AM35XX_CONTROL_LVL_INTR_CLEAR);
352 /* write EOI */
353 musb_writel(reg_base, USB_END_OF_INTR_REG, 0);
354 }
355
356 /* Poll for ID change */
357 if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE)
358 mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
359
360 spin_unlock_irqrestore(&musb->lock, flags);
361
362 return ret;
363}
364
365int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
366{
367 u32 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
368
369 devconf2 &= ~CONF2_OTGMODE;
370 switch (musb_mode) {
371#ifdef CONFIG_USB_MUSB_HDRC_HCD
372 case MUSB_HOST: /* Force VBUS valid, ID = 0 */
373 devconf2 |= CONF2_FORCE_HOST;
374 break;
375#endif
376#ifdef CONFIG_USB_GADGET_MUSB_HDRC
377 case MUSB_PERIPHERAL: /* Force VBUS valid, ID = 1 */
378 devconf2 |= CONF2_FORCE_DEVICE;
379 break;
380#endif
381#ifdef CONFIG_USB_MUSB_OTG
382 case MUSB_OTG: /* Don't override the VBUS/ID comparators */
383 devconf2 |= CONF2_NO_OVERRIDE;
384 break;
385#endif
386 default:
387 DBG(2, "Trying to set unsupported mode %u\n", musb_mode);
388 }
389
390 omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
391 return 0;
392}
393
394int __init musb_platform_init(struct musb *musb, void *board_data)
395{
396 void __iomem *reg_base = musb->ctrl_base;
397 u32 rev, lvl_intr, sw_reset;
398 int status;
399
400 musb->mregs += USB_MENTOR_CORE_OFFSET;
401
402 clk_enable(musb->clock);
403 DBG(2, "musb->clock=%lud\n", clk_get_rate(musb->clock));
404
405 musb->phy_clock = clk_get(musb->controller, "fck");
406 if (IS_ERR(musb->phy_clock)) {
407 status = PTR_ERR(musb->phy_clock);
408 goto exit0;
409 }
410 clk_enable(musb->phy_clock);
411 DBG(2, "musb->phy_clock=%lud\n", clk_get_rate(musb->phy_clock));
412
413 /* Returns zero if e.g. not clocked */
414 rev = musb_readl(reg_base, USB_REVISION_REG);
415 if (!rev) {
416 status = -ENODEV;
417 goto exit1;
418 }
419
420 usb_nop_xceiv_register();
421 musb->xceiv = otg_get_transceiver();
422 if (!musb->xceiv) {
423 status = -ENODEV;
424 goto exit1;
425 }
426
427 if (is_host_enabled(musb))
428 setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
429
430 musb->board_set_vbus = am35x_set_vbus;
431
432 /* Global reset */
433 sw_reset = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
434
435 sw_reset |= AM35XX_USBOTGSS_SW_RST;
436 omap_ctrl_writel(sw_reset, AM35XX_CONTROL_IP_SW_RESET);
437
438 sw_reset &= ~AM35XX_USBOTGSS_SW_RST;
439 omap_ctrl_writel(sw_reset, AM35XX_CONTROL_IP_SW_RESET);
440
441 /* Reset the controller */
442 musb_writel(reg_base, USB_CTRL_REG, AM35X_SOFT_RESET_MASK);
443
444 /* Start the on-chip PHY and its PLL. */
445 phy_on();
446
447 msleep(5);
448
449 musb->isr = am35x_interrupt;
450
451 /* clear level interrupt */
452 lvl_intr = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
453 lvl_intr |= AM35XX_USBOTGSS_INT_CLR;
454 omap_ctrl_writel(lvl_intr, AM35XX_CONTROL_LVL_INTR_CLEAR);
455 return 0;
456exit1:
457 clk_disable(musb->phy_clock);
458 clk_put(musb->phy_clock);
459exit0:
460 clk_disable(musb->clock);
461 return status;
462}
463
464int musb_platform_exit(struct musb *musb)
465{
466 if (is_host_enabled(musb))
467 del_timer_sync(&otg_workaround);
468
469 phy_off();
470
471 otg_put_transceiver(musb->xceiv);
472 usb_nop_xceiv_unregister();
473
474 clk_disable(musb->clock);
475
476 clk_disable(musb->phy_clock);
477 clk_put(musb->phy_clock);
478
479 return 0;
480}
481
482#ifdef CONFIG_PM
483void musb_platform_save_context(struct musb *musb,
484 struct musb_context_registers *musb_context)
485{
486 phy_off();
487}
488
489void musb_platform_restore_context(struct musb *musb,
490 struct musb_context_registers *musb_context)
491{
492 phy_on();
493}
494#endif
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 2a8236216dc7..69797e5b46a7 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -330,6 +330,7 @@ struct musb {
330 /* device lock */ 330 /* device lock */
331 spinlock_t lock; 331 spinlock_t lock;
332 struct clk *clock; 332 struct clk *clock;
333 struct clk *phy_clock;
333 irqreturn_t (*isr)(int, void *); 334 irqreturn_t (*isr)(int, void *);
334 struct work_struct irq_work; 335 struct work_struct irq_work;
335 u16 hwvers; 336 u16 hwvers;