diff options
-rw-r--r-- | drivers/usb/musb/musb_core.h | 1 | ||||
-rw-r--r-- | drivers/usb/musb/omap2430.c | 109 |
2 files changed, 99 insertions, 11 deletions
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index b9ea563d1c8e..d0c236f8e191 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h | |||
@@ -411,6 +411,7 @@ struct musb { | |||
411 | 411 | ||
412 | struct timer_list otg_timer; | 412 | struct timer_list otg_timer; |
413 | #endif | 413 | #endif |
414 | struct notifier_block nb; | ||
414 | 415 | ||
415 | struct dma_controller *dma_controller; | 416 | struct dma_controller *dma_controller; |
416 | 417 | ||
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 0a7e6824eae8..a3f12333fc41 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c | |||
@@ -57,12 +57,8 @@ static void musb_do_idle(unsigned long _musb) | |||
57 | 57 | ||
58 | spin_lock_irqsave(&musb->lock, flags); | 58 | spin_lock_irqsave(&musb->lock, flags); |
59 | 59 | ||
60 | devctl = musb_readb(musb->mregs, MUSB_DEVCTL); | ||
61 | |||
62 | switch (musb->xceiv->state) { | 60 | switch (musb->xceiv->state) { |
63 | case OTG_STATE_A_WAIT_BCON: | 61 | case OTG_STATE_A_WAIT_BCON: |
64 | devctl &= ~MUSB_DEVCTL_SESSION; | ||
65 | musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); | ||
66 | 62 | ||
67 | devctl = musb_readb(musb->mregs, MUSB_DEVCTL); | 63 | devctl = musb_readb(musb->mregs, MUSB_DEVCTL); |
68 | if (devctl & MUSB_DEVCTL_BDEVICE) { | 64 | if (devctl & MUSB_DEVCTL_BDEVICE) { |
@@ -142,6 +138,8 @@ static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout) | |||
142 | static void omap2430_musb_set_vbus(struct musb *musb, int is_on) | 138 | static void omap2430_musb_set_vbus(struct musb *musb, int is_on) |
143 | { | 139 | { |
144 | u8 devctl; | 140 | u8 devctl; |
141 | unsigned long timeout = jiffies + msecs_to_jiffies(1000); | ||
142 | int ret = 1; | ||
145 | /* HDRC controls CPEN, but beware current surges during device | 143 | /* HDRC controls CPEN, but beware current surges during device |
146 | * connect. They can trigger transient overcurrent conditions | 144 | * connect. They can trigger transient overcurrent conditions |
147 | * that must be ignored. | 145 | * that must be ignored. |
@@ -150,12 +148,35 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on) | |||
150 | devctl = musb_readb(musb->mregs, MUSB_DEVCTL); | 148 | devctl = musb_readb(musb->mregs, MUSB_DEVCTL); |
151 | 149 | ||
152 | if (is_on) { | 150 | if (is_on) { |
153 | musb->is_active = 1; | 151 | if (musb->xceiv->state == OTG_STATE_A_IDLE) { |
154 | musb->xceiv->default_a = 1; | 152 | /* start the session */ |
155 | musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; | 153 | devctl |= MUSB_DEVCTL_SESSION; |
156 | devctl |= MUSB_DEVCTL_SESSION; | 154 | musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); |
157 | 155 | /* | |
158 | MUSB_HST_MODE(musb); | 156 | * Wait for the musb to set as A device to enable the |
157 | * VBUS | ||
158 | */ | ||
159 | while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) { | ||
160 | |||
161 | cpu_relax(); | ||
162 | |||
163 | if (time_after(jiffies, timeout)) { | ||
164 | dev_err(musb->controller, | ||
165 | "configured as A device timeout"); | ||
166 | ret = -EINVAL; | ||
167 | break; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | if (ret && musb->xceiv->set_vbus) | ||
172 | otg_set_vbus(musb->xceiv, 1); | ||
173 | } else { | ||
174 | musb->is_active = 1; | ||
175 | musb->xceiv->default_a = 1; | ||
176 | musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; | ||
177 | devctl |= MUSB_DEVCTL_SESSION; | ||
178 | MUSB_HST_MODE(musb); | ||
179 | } | ||
159 | } else { | 180 | } else { |
160 | musb->is_active = 0; | 181 | musb->is_active = 0; |
161 | 182 | ||
@@ -214,9 +235,64 @@ static inline void omap2430_low_level_init(struct musb *musb) | |||
214 | musb_writel(musb->mregs, OTG_FORCESTDBY, l); | 235 | musb_writel(musb->mregs, OTG_FORCESTDBY, l); |
215 | } | 236 | } |
216 | 237 | ||
238 | /* blocking notifier support */ | ||
239 | static int musb_otg_notifications(struct notifier_block *nb, | ||
240 | unsigned long event, void *unused) | ||
241 | { | ||
242 | struct musb *musb = container_of(nb, struct musb, nb); | ||
243 | struct device *dev = musb->controller; | ||
244 | struct musb_hdrc_platform_data *pdata = dev->platform_data; | ||
245 | struct omap_musb_board_data *data = pdata->board_data; | ||
246 | |||
247 | switch (event) { | ||
248 | case USB_EVENT_ID: | ||
249 | DBG(4, "ID GND\n"); | ||
250 | |||
251 | if (is_otg_enabled(musb)) { | ||
252 | #ifdef CONFIG_USB_GADGET_MUSB_HDRC | ||
253 | if (musb->gadget_driver) { | ||
254 | otg_init(musb->xceiv); | ||
255 | |||
256 | if (data->interface_type == | ||
257 | MUSB_INTERFACE_UTMI) | ||
258 | omap2430_musb_set_vbus(musb, 1); | ||
259 | |||
260 | } | ||
261 | #endif | ||
262 | } else { | ||
263 | otg_init(musb->xceiv); | ||
264 | if (data->interface_type == | ||
265 | MUSB_INTERFACE_UTMI) | ||
266 | omap2430_musb_set_vbus(musb, 1); | ||
267 | } | ||
268 | break; | ||
269 | |||
270 | case USB_EVENT_VBUS: | ||
271 | DBG(4, "VBUS Connect\n"); | ||
272 | |||
273 | otg_init(musb->xceiv); | ||
274 | break; | ||
275 | |||
276 | case USB_EVENT_NONE: | ||
277 | DBG(4, "VBUS Disconnect\n"); | ||
278 | |||
279 | if (data->interface_type == MUSB_INTERFACE_UTMI) { | ||
280 | if (musb->xceiv->set_vbus) | ||
281 | otg_set_vbus(musb->xceiv, 0); | ||
282 | } | ||
283 | otg_shutdown(musb->xceiv); | ||
284 | break; | ||
285 | default: | ||
286 | DBG(4, "ID float\n"); | ||
287 | return NOTIFY_DONE; | ||
288 | } | ||
289 | |||
290 | return NOTIFY_OK; | ||
291 | } | ||
292 | |||
217 | static int omap2430_musb_init(struct musb *musb) | 293 | static int omap2430_musb_init(struct musb *musb) |
218 | { | 294 | { |
219 | u32 l; | 295 | u32 l, status = 0; |
220 | struct device *dev = musb->controller; | 296 | struct device *dev = musb->controller; |
221 | struct musb_hdrc_platform_data *plat = dev->platform_data; | 297 | struct musb_hdrc_platform_data *plat = dev->platform_data; |
222 | struct omap_musb_board_data *data = plat->board_data; | 298 | struct omap_musb_board_data *data = plat->board_data; |
@@ -268,6 +344,17 @@ static int omap2430_musb_init(struct musb *musb) | |||
268 | musb_readl(musb->mregs, OTG_INTERFSEL), | 344 | musb_readl(musb->mregs, OTG_INTERFSEL), |
269 | musb_readl(musb->mregs, OTG_SIMENABLE)); | 345 | musb_readl(musb->mregs, OTG_SIMENABLE)); |
270 | 346 | ||
347 | musb->nb.notifier_call = musb_otg_notifications; | ||
348 | status = otg_register_notifier(musb->xceiv, &musb->nb); | ||
349 | |||
350 | if (status) | ||
351 | DBG(1, "notification register failed\n"); | ||
352 | |||
353 | /* check whether cable is already connected */ | ||
354 | if (musb->xceiv->state ==OTG_STATE_B_IDLE) | ||
355 | musb_otg_notifications(&musb->nb, 1, | ||
356 | musb->xceiv->gadget); | ||
357 | |||
271 | setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); | 358 | setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); |
272 | 359 | ||
273 | return 0; | 360 | return 0; |