aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/musb/musb_core.h1
-rw-r--r--drivers/usb/musb/omap2430.c109
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)
142static void omap2430_musb_set_vbus(struct musb *musb, int is_on) 138static 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 */
239static 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
217static int omap2430_musb_init(struct musb *musb) 293static 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;