aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/musb/omap2430.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/musb/omap2430.c')
-rw-r--r--drivers/usb/musb/omap2430.c257
1 files changed, 89 insertions, 168 deletions
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index c84e0322c108..0b4cec940386 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -49,97 +49,14 @@ struct omap2430_glue {
49 enum musb_vbus_id_status status; 49 enum musb_vbus_id_status status;
50 struct work_struct omap_musb_mailbox_work; 50 struct work_struct omap_musb_mailbox_work;
51 struct device *control_otghs; 51 struct device *control_otghs;
52 bool cable_connected;
53 bool enabled;
54 bool powered;
52}; 55};
53#define glue_to_musb(g) platform_get_drvdata(g->musb) 56#define glue_to_musb(g) platform_get_drvdata(g->musb)
54 57
55static struct omap2430_glue *_glue; 58static struct omap2430_glue *_glue;
56 59
57static struct timer_list musb_idle_timer;
58
59static void musb_do_idle(unsigned long _musb)
60{
61 struct musb *musb = (void *)_musb;
62 unsigned long flags;
63 u8 power;
64 u8 devctl;
65
66 spin_lock_irqsave(&musb->lock, flags);
67
68 switch (musb->xceiv->otg->state) {
69 case OTG_STATE_A_WAIT_BCON:
70
71 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
72 if (devctl & MUSB_DEVCTL_BDEVICE) {
73 musb->xceiv->otg->state = OTG_STATE_B_IDLE;
74 MUSB_DEV_MODE(musb);
75 } else {
76 musb->xceiv->otg->state = OTG_STATE_A_IDLE;
77 MUSB_HST_MODE(musb);
78 }
79 break;
80 case OTG_STATE_A_SUSPEND:
81 /* finish RESUME signaling? */
82 if (musb->port1_status & MUSB_PORT_STAT_RESUME) {
83 power = musb_readb(musb->mregs, MUSB_POWER);
84 power &= ~MUSB_POWER_RESUME;
85 dev_dbg(musb->controller, "root port resume stopped, power %02x\n", power);
86 musb_writeb(musb->mregs, MUSB_POWER, power);
87 musb->is_active = 1;
88 musb->port1_status &= ~(USB_PORT_STAT_SUSPEND
89 | MUSB_PORT_STAT_RESUME);
90 musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
91 usb_hcd_poll_rh_status(musb->hcd);
92 /* NOTE: it might really be A_WAIT_BCON ... */
93 musb->xceiv->otg->state = OTG_STATE_A_HOST;
94 }
95 break;
96 case OTG_STATE_A_HOST:
97 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
98 if (devctl & MUSB_DEVCTL_BDEVICE)
99 musb->xceiv->otg->state = OTG_STATE_B_IDLE;
100 else
101 musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON;
102 default:
103 break;
104 }
105 spin_unlock_irqrestore(&musb->lock, flags);
106}
107
108
109static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
110{
111 unsigned long default_timeout = jiffies + msecs_to_jiffies(3);
112 static unsigned long last_timer;
113
114 if (timeout == 0)
115 timeout = default_timeout;
116
117 /* Never idle if active, or when VBUS timeout is not set as host */
118 if (musb->is_active || ((musb->a_wait_bcon == 0)
119 && (musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON))) {
120 dev_dbg(musb->controller, "%s active, deleting timer\n",
121 usb_otg_state_string(musb->xceiv->otg->state));
122 del_timer(&musb_idle_timer);
123 last_timer = jiffies;
124 return;
125 }
126
127 if (time_after(last_timer, timeout)) {
128 if (!timer_pending(&musb_idle_timer))
129 last_timer = timeout;
130 else {
131 dev_dbg(musb->controller, "Longer idle timer already pending, ignoring\n");
132 return;
133 }
134 }
135 last_timer = timeout;
136
137 dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n",
138 usb_otg_state_string(musb->xceiv->otg->state),
139 (unsigned long)jiffies_to_msecs(timeout - jiffies));
140 mod_timer(&musb_idle_timer, timeout);
141}
142
143static void omap2430_musb_set_vbus(struct musb *musb, int is_on) 60static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
144{ 61{
145 struct usb_otg *otg = musb->xceiv->otg; 62 struct usb_otg *otg = musb->xceiv->otg;
@@ -205,16 +122,6 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
205 musb_readb(musb->mregs, MUSB_DEVCTL)); 122 musb_readb(musb->mregs, MUSB_DEVCTL));
206} 123}
207 124
208static int omap2430_musb_set_mode(struct musb *musb, u8 musb_mode)
209{
210 u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
211
212 devctl |= MUSB_DEVCTL_SESSION;
213 musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
214
215 return 0;
216}
217
218static inline void omap2430_low_level_exit(struct musb *musb) 125static inline void omap2430_low_level_exit(struct musb *musb)
219{ 126{
220 u32 l; 127 u32 l;
@@ -234,22 +141,63 @@ static inline void omap2430_low_level_init(struct musb *musb)
234 musb_writel(musb->mregs, OTG_FORCESTDBY, l); 141 musb_writel(musb->mregs, OTG_FORCESTDBY, l);
235} 142}
236 143
237static void omap2430_musb_mailbox(enum musb_vbus_id_status status) 144/*
145 * We can get multiple cable events so we need to keep track
146 * of the power state. Only keep power enabled if USB cable is
147 * connected and a gadget is started.
148 */
149static void omap2430_set_power(struct musb *musb, bool enabled, bool cable)
150{
151 struct device *dev = musb->controller;
152 struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
153 bool power_up;
154 int res;
155
156 if (glue->enabled != enabled)
157 glue->enabled = enabled;
158
159 if (glue->cable_connected != cable)
160 glue->cable_connected = cable;
161
162 power_up = glue->enabled && glue->cable_connected;
163 if (power_up == glue->powered) {
164 dev_warn(musb->controller, "power state already %i\n",
165 power_up);
166 return;
167 }
168
169 glue->powered = power_up;
170
171 if (power_up) {
172 res = pm_runtime_get_sync(musb->controller);
173 if (res < 0) {
174 dev_err(musb->controller, "could not enable: %i", res);
175 glue->powered = false;
176 }
177 } else {
178 pm_runtime_mark_last_busy(musb->controller);
179 pm_runtime_put_autosuspend(musb->controller);
180 }
181}
182
183static int omap2430_musb_mailbox(enum musb_vbus_id_status status)
238{ 184{
239 struct omap2430_glue *glue = _glue; 185 struct omap2430_glue *glue = _glue;
240 186
241 if (!glue) { 187 if (!glue) {
242 pr_err("%s: musb core is not yet initialized\n", __func__); 188 pr_err("%s: musb core is not yet initialized\n", __func__);
243 return; 189 return -EPROBE_DEFER;
244 } 190 }
245 glue->status = status; 191 glue->status = status;
246 192
247 if (!glue_to_musb(glue)) { 193 if (!glue_to_musb(glue)) {
248 pr_err("%s: musb core is not yet ready\n", __func__); 194 pr_err("%s: musb core is not yet ready\n", __func__);
249 return; 195 return -EPROBE_DEFER;
250 } 196 }
251 197
252 schedule_work(&glue->omap_musb_mailbox_work); 198 schedule_work(&glue->omap_musb_mailbox_work);
199
200 return 0;
253} 201}
254 202
255static void omap_musb_set_mailbox(struct omap2430_glue *glue) 203static void omap_musb_set_mailbox(struct omap2430_glue *glue)
@@ -259,6 +207,13 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
259 struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev); 207 struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev);
260 struct omap_musb_board_data *data = pdata->board_data; 208 struct omap_musb_board_data *data = pdata->board_data;
261 struct usb_otg *otg = musb->xceiv->otg; 209 struct usb_otg *otg = musb->xceiv->otg;
210 bool cable_connected;
211
212 cable_connected = ((glue->status == MUSB_ID_GROUND) ||
213 (glue->status == MUSB_VBUS_VALID));
214
215 if (cable_connected)
216 omap2430_set_power(musb, glue->enabled, cable_connected);
262 217
263 switch (glue->status) { 218 switch (glue->status) {
264 case MUSB_ID_GROUND: 219 case MUSB_ID_GROUND:
@@ -268,7 +223,6 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
268 musb->xceiv->otg->state = OTG_STATE_A_IDLE; 223 musb->xceiv->otg->state = OTG_STATE_A_IDLE;
269 musb->xceiv->last_event = USB_EVENT_ID; 224 musb->xceiv->last_event = USB_EVENT_ID;
270 if (musb->gadget_driver) { 225 if (musb->gadget_driver) {
271 pm_runtime_get_sync(dev);
272 omap_control_usb_set_mode(glue->control_otghs, 226 omap_control_usb_set_mode(glue->control_otghs,
273 USB_MODE_HOST); 227 USB_MODE_HOST);
274 omap2430_musb_set_vbus(musb, 1); 228 omap2430_musb_set_vbus(musb, 1);
@@ -281,8 +235,6 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
281 otg->default_a = false; 235 otg->default_a = false;
282 musb->xceiv->otg->state = OTG_STATE_B_IDLE; 236 musb->xceiv->otg->state = OTG_STATE_B_IDLE;
283 musb->xceiv->last_event = USB_EVENT_VBUS; 237 musb->xceiv->last_event = USB_EVENT_VBUS;
284 if (musb->gadget_driver)
285 pm_runtime_get_sync(dev);
286 omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE); 238 omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE);
287 break; 239 break;
288 240
@@ -291,11 +243,8 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
291 dev_dbg(dev, "VBUS Disconnect\n"); 243 dev_dbg(dev, "VBUS Disconnect\n");
292 244
293 musb->xceiv->last_event = USB_EVENT_NONE; 245 musb->xceiv->last_event = USB_EVENT_NONE;
294 if (musb->gadget_driver) { 246 if (musb->gadget_driver)
295 omap2430_musb_set_vbus(musb, 0); 247 omap2430_musb_set_vbus(musb, 0);
296 pm_runtime_mark_last_busy(dev);
297 pm_runtime_put_autosuspend(dev);
298 }
299 248
300 if (data->interface_type == MUSB_INTERFACE_UTMI) 249 if (data->interface_type == MUSB_INTERFACE_UTMI)
301 otg_set_vbus(musb->xceiv->otg, 0); 250 otg_set_vbus(musb->xceiv->otg, 0);
@@ -307,6 +256,9 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
307 dev_dbg(dev, "ID float\n"); 256 dev_dbg(dev, "ID float\n");
308 } 257 }
309 258
259 if (!cable_connected)
260 omap2430_set_power(musb, glue->enabled, cable_connected);
261
310 atomic_notifier_call_chain(&musb->xceiv->notifier, 262 atomic_notifier_call_chain(&musb->xceiv->notifier,
311 musb->xceiv->last_event, NULL); 263 musb->xceiv->last_event, NULL);
312} 264}
@@ -316,13 +268,8 @@ static void omap_musb_mailbox_work(struct work_struct *mailbox_work)
316{ 268{
317 struct omap2430_glue *glue = container_of(mailbox_work, 269 struct omap2430_glue *glue = container_of(mailbox_work,
318 struct omap2430_glue, omap_musb_mailbox_work); 270 struct omap2430_glue, omap_musb_mailbox_work);
319 struct musb *musb = glue_to_musb(glue);
320 struct device *dev = musb->controller;
321 271
322 pm_runtime_get_sync(dev);
323 omap_musb_set_mailbox(glue); 272 omap_musb_set_mailbox(glue);
324 pm_runtime_mark_last_busy(dev);
325 pm_runtime_put_autosuspend(dev);
326} 273}
327 274
328static irqreturn_t omap2430_musb_interrupt(int irq, void *__hci) 275static irqreturn_t omap2430_musb_interrupt(int irq, void *__hci)
@@ -389,23 +336,7 @@ static int omap2430_musb_init(struct musb *musb)
389 return PTR_ERR(musb->phy); 336 return PTR_ERR(musb->phy);
390 } 337 }
391 musb->isr = omap2430_musb_interrupt; 338 musb->isr = omap2430_musb_interrupt;
392 339 phy_init(musb->phy);
393 /*
394 * Enable runtime PM for musb parent (this driver). We can't
395 * do it earlier as struct musb is not yet allocated and we
396 * need to touch the musb registers for runtime PM.
397 */
398 pm_runtime_enable(glue->dev);
399 status = pm_runtime_get_sync(glue->dev);
400 if (status < 0)
401 goto err1;
402
403 status = pm_runtime_get_sync(dev);
404 if (status < 0) {
405 dev_err(dev, "pm_runtime_get_sync FAILED %d\n", status);
406 pm_runtime_put_sync(glue->dev);
407 goto err1;
408 }
409 340
410 l = musb_readl(musb->mregs, OTG_INTERFSEL); 341 l = musb_readl(musb->mregs, OTG_INTERFSEL);
411 342
@@ -427,20 +358,10 @@ static int omap2430_musb_init(struct musb *musb)
427 musb_readl(musb->mregs, OTG_INTERFSEL), 358 musb_readl(musb->mregs, OTG_INTERFSEL),
428 musb_readl(musb->mregs, OTG_SIMENABLE)); 359 musb_readl(musb->mregs, OTG_SIMENABLE));
429 360
430 setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
431
432 if (glue->status != MUSB_UNKNOWN) 361 if (glue->status != MUSB_UNKNOWN)
433 omap_musb_set_mailbox(glue); 362 omap_musb_set_mailbox(glue);
434 363
435 phy_init(musb->phy);
436 phy_power_on(musb->phy);
437
438 pm_runtime_put_noidle(musb->controller);
439 pm_runtime_put_noidle(glue->dev);
440 return 0; 364 return 0;
441
442err1:
443 return status;
444} 365}
445 366
446static void omap2430_musb_enable(struct musb *musb) 367static void omap2430_musb_enable(struct musb *musb)
@@ -452,6 +373,11 @@ static void omap2430_musb_enable(struct musb *musb)
452 struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev); 373 struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev);
453 struct omap_musb_board_data *data = pdata->board_data; 374 struct omap_musb_board_data *data = pdata->board_data;
454 375
376 if (!WARN_ON(!musb->phy))
377 phy_power_on(musb->phy);
378
379 omap2430_set_power(musb, true, glue->cable_connected);
380
455 switch (glue->status) { 381 switch (glue->status) {
456 382
457 case MUSB_ID_GROUND: 383 case MUSB_ID_GROUND:
@@ -487,18 +413,25 @@ static void omap2430_musb_disable(struct musb *musb)
487 struct device *dev = musb->controller; 413 struct device *dev = musb->controller;
488 struct omap2430_glue *glue = dev_get_drvdata(dev->parent); 414 struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
489 415
416 if (!WARN_ON(!musb->phy))
417 phy_power_off(musb->phy);
418
490 if (glue->status != MUSB_UNKNOWN) 419 if (glue->status != MUSB_UNKNOWN)
491 omap_control_usb_set_mode(glue->control_otghs, 420 omap_control_usb_set_mode(glue->control_otghs,
492 USB_MODE_DISCONNECT); 421 USB_MODE_DISCONNECT);
422
423 omap2430_set_power(musb, false, glue->cable_connected);
493} 424}
494 425
495static int omap2430_musb_exit(struct musb *musb) 426static int omap2430_musb_exit(struct musb *musb)
496{ 427{
497 del_timer_sync(&musb_idle_timer); 428 struct device *dev = musb->controller;
429 struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
498 430
499 omap2430_low_level_exit(musb); 431 omap2430_low_level_exit(musb);
500 phy_power_off(musb->phy);
501 phy_exit(musb->phy); 432 phy_exit(musb->phy);
433 musb->phy = NULL;
434 cancel_work_sync(&glue->omap_musb_mailbox_work);
502 435
503 return 0; 436 return 0;
504} 437}
@@ -512,9 +445,6 @@ static const struct musb_platform_ops omap2430_ops = {
512 .init = omap2430_musb_init, 445 .init = omap2430_musb_init,
513 .exit = omap2430_musb_exit, 446 .exit = omap2430_musb_exit,
514 447
515 .set_mode = omap2430_musb_set_mode,
516 .try_idle = omap2430_musb_try_idle,
517
518 .set_vbus = omap2430_musb_set_vbus, 448 .set_vbus = omap2430_musb_set_vbus,
519 449
520 .enable = omap2430_musb_enable, 450 .enable = omap2430_musb_enable,
@@ -639,11 +569,9 @@ static int omap2430_probe(struct platform_device *pdev)
639 goto err2; 569 goto err2;
640 } 570 }
641 571
642 /* 572 pm_runtime_enable(glue->dev);
643 * Note that we cannot enable PM runtime yet for this 573 pm_runtime_use_autosuspend(glue->dev);
644 * driver as we need struct musb initialized first. 574 pm_runtime_set_autosuspend_delay(glue->dev, 500);
645 * See omap2430_musb_init above.
646 */
647 575
648 ret = platform_device_add(musb); 576 ret = platform_device_add(musb);
649 if (ret) { 577 if (ret) {
@@ -662,12 +590,14 @@ err0:
662 590
663static int omap2430_remove(struct platform_device *pdev) 591static int omap2430_remove(struct platform_device *pdev)
664{ 592{
665 struct omap2430_glue *glue = platform_get_drvdata(pdev); 593 struct omap2430_glue *glue = platform_get_drvdata(pdev);
594 struct musb *musb = glue_to_musb(glue);
666 595
667 pm_runtime_get_sync(glue->dev); 596 pm_runtime_get_sync(glue->dev);
668 cancel_work_sync(&glue->omap_musb_mailbox_work);
669 platform_device_unregister(glue->musb); 597 platform_device_unregister(glue->musb);
598 omap2430_set_power(musb, false, false);
670 pm_runtime_put_sync(glue->dev); 599 pm_runtime_put_sync(glue->dev);
600 pm_runtime_dont_use_autosuspend(glue->dev);
671 pm_runtime_disable(glue->dev); 601 pm_runtime_disable(glue->dev);
672 602
673 return 0; 603 return 0;
@@ -680,12 +610,13 @@ static int omap2430_runtime_suspend(struct device *dev)
680 struct omap2430_glue *glue = dev_get_drvdata(dev); 610 struct omap2430_glue *glue = dev_get_drvdata(dev);
681 struct musb *musb = glue_to_musb(glue); 611 struct musb *musb = glue_to_musb(glue);
682 612
683 if (musb) { 613 if (!musb)
684 musb->context.otg_interfsel = musb_readl(musb->mregs, 614 return 0;
685 OTG_INTERFSEL);
686 615
687 omap2430_low_level_exit(musb); 616 musb->context.otg_interfsel = musb_readl(musb->mregs,
688 } 617 OTG_INTERFSEL);
618
619 omap2430_low_level_exit(musb);
689 620
690 return 0; 621 return 0;
691} 622}
@@ -696,7 +627,7 @@ static int omap2430_runtime_resume(struct device *dev)
696 struct musb *musb = glue_to_musb(glue); 627 struct musb *musb = glue_to_musb(glue);
697 628
698 if (!musb) 629 if (!musb)
699 return -EPROBE_DEFER; 630 return 0;
700 631
701 omap2430_low_level_init(musb); 632 omap2430_low_level_init(musb);
702 musb_writel(musb->mregs, OTG_INTERFSEL, 633 musb_writel(musb->mregs, OTG_INTERFSEL,
@@ -738,18 +669,8 @@ static struct platform_driver omap2430_driver = {
738 }, 669 },
739}; 670};
740 671
672module_platform_driver(omap2430_driver);
673
741MODULE_DESCRIPTION("OMAP2PLUS MUSB Glue Layer"); 674MODULE_DESCRIPTION("OMAP2PLUS MUSB Glue Layer");
742MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); 675MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
743MODULE_LICENSE("GPL v2"); 676MODULE_LICENSE("GPL v2");
744
745static int __init omap2430_init(void)
746{
747 return platform_driver_register(&omap2430_driver);
748}
749subsys_initcall(omap2430_init);
750
751static void __exit omap2430_exit(void)
752{
753 platform_driver_unregister(&omap2430_driver);
754}
755module_exit(omap2430_exit);