diff options
author | B, Ravi <ravibabu@ti.com> | 2012-08-31 07:09:51 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2012-09-11 10:35:44 -0400 |
commit | db4a93202e086dbdb5789149666dbbff48f708bf (patch) | |
tree | b4608556b3c7aff82bad75bc94219fa7ba377241 | |
parent | 8d2421e68cb8a159963641eab72f8f8ba1c7f7b0 (diff) |
usb: musb: am335x: add support for dual instance
AM335x and TI81xx platform has dual musb controller so updating the
musb_dspc.c to support the same.
Changes:
- Moved otg_workaround timer to glue structure
- Moved static local variable last_timer to glue structure
- PHY on/off related cleanups
Signed-off-by: Ravi Babu <ravibabu@ti.com>
Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com>
Signed-off-by: Santhapuri, Damodar <damodar.santhapuri@ti.com>
[afzal@ti.com: remove control module related modifications]
Signed-off-by: Afzal Mohammed <afzal@ti.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r-- | drivers/usb/musb/musb_dsps.c | 81 |
1 files changed, 49 insertions, 32 deletions
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 5351e960d650..796fc6085fce 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c | |||
@@ -105,6 +105,8 @@ struct dsps_musb_wrapper { | |||
105 | /* miscellaneous stuff */ | 105 | /* miscellaneous stuff */ |
106 | u32 musb_core_offset; | 106 | u32 musb_core_offset; |
107 | u8 poll_seconds; | 107 | u8 poll_seconds; |
108 | /* number of musb instances */ | ||
109 | u8 instances; | ||
108 | }; | 110 | }; |
109 | 111 | ||
110 | /** | 112 | /** |
@@ -112,9 +114,10 @@ struct dsps_musb_wrapper { | |||
112 | */ | 114 | */ |
113 | struct dsps_glue { | 115 | struct dsps_glue { |
114 | struct device *dev; | 116 | struct device *dev; |
115 | struct platform_device *musb; /* child musb pdev */ | 117 | struct platform_device *musb[2]; /* child musb pdev */ |
116 | const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ | 118 | const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ |
117 | struct timer_list timer; /* otg_workaround timer */ | 119 | struct timer_list timer[2]; /* otg_workaround timer */ |
120 | unsigned long last_timer[2]; /* last timer data for each instance */ | ||
118 | }; | 121 | }; |
119 | 122 | ||
120 | /** | 123 | /** |
@@ -164,8 +167,8 @@ static void otg_timer(unsigned long _musb) | |||
164 | struct musb *musb = (void *)_musb; | 167 | struct musb *musb = (void *)_musb; |
165 | void __iomem *mregs = musb->mregs; | 168 | void __iomem *mregs = musb->mregs; |
166 | struct device *dev = musb->controller; | 169 | struct device *dev = musb->controller; |
167 | struct platform_device *pdev = to_platform_device(dev->parent); | 170 | struct platform_device *pdev = to_platform_device(dev); |
168 | struct dsps_glue *glue = platform_get_drvdata(pdev); | 171 | struct dsps_glue *glue = dev_get_drvdata(dev->parent); |
169 | const struct dsps_musb_wrapper *wrp = glue->wrp; | 172 | const struct dsps_musb_wrapper *wrp = glue->wrp; |
170 | u8 devctl; | 173 | u8 devctl; |
171 | unsigned long flags; | 174 | unsigned long flags; |
@@ -201,7 +204,7 @@ static void otg_timer(unsigned long _musb) | |||
201 | case OTG_STATE_B_IDLE: | 204 | case OTG_STATE_B_IDLE: |
202 | devctl = dsps_readb(mregs, MUSB_DEVCTL); | 205 | devctl = dsps_readb(mregs, MUSB_DEVCTL); |
203 | if (devctl & MUSB_DEVCTL_BDEVICE) | 206 | if (devctl & MUSB_DEVCTL_BDEVICE) |
204 | mod_timer(&glue->timer, | 207 | mod_timer(&glue->timer[pdev->id], |
205 | jiffies + wrp->poll_seconds * HZ); | 208 | jiffies + wrp->poll_seconds * HZ); |
206 | else | 209 | else |
207 | musb->xceiv->state = OTG_STATE_A_IDLE; | 210 | musb->xceiv->state = OTG_STATE_A_IDLE; |
@@ -215,9 +218,8 @@ static void otg_timer(unsigned long _musb) | |||
215 | static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) | 218 | static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) |
216 | { | 219 | { |
217 | struct device *dev = musb->controller; | 220 | struct device *dev = musb->controller; |
218 | struct platform_device *pdev = to_platform_device(dev->parent); | 221 | struct platform_device *pdev = to_platform_device(dev); |
219 | struct dsps_glue *glue = platform_get_drvdata(pdev); | 222 | struct dsps_glue *glue = dev_get_drvdata(dev->parent); |
220 | static unsigned long last_timer; | ||
221 | 223 | ||
222 | if (timeout == 0) | 224 | if (timeout == 0) |
223 | timeout = jiffies + msecs_to_jiffies(3); | 225 | timeout = jiffies + msecs_to_jiffies(3); |
@@ -227,22 +229,23 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) | |||
227 | musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { | 229 | musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { |
228 | dev_dbg(musb->controller, "%s active, deleting timer\n", | 230 | dev_dbg(musb->controller, "%s active, deleting timer\n", |
229 | otg_state_string(musb->xceiv->state)); | 231 | otg_state_string(musb->xceiv->state)); |
230 | del_timer(&glue->timer); | 232 | del_timer(&glue->timer[pdev->id]); |
231 | last_timer = jiffies; | 233 | glue->last_timer[pdev->id] = jiffies; |
232 | return; | 234 | return; |
233 | } | 235 | } |
234 | 236 | ||
235 | if (time_after(last_timer, timeout) && timer_pending(&glue->timer)) { | 237 | if (time_after(glue->last_timer[pdev->id], timeout) && |
238 | timer_pending(&glue->timer[pdev->id])) { | ||
236 | dev_dbg(musb->controller, | 239 | dev_dbg(musb->controller, |
237 | "Longer idle timer already pending, ignoring...\n"); | 240 | "Longer idle timer already pending, ignoring...\n"); |
238 | return; | 241 | return; |
239 | } | 242 | } |
240 | last_timer = timeout; | 243 | glue->last_timer[pdev->id] = timeout; |
241 | 244 | ||
242 | dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", | 245 | dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", |
243 | otg_state_string(musb->xceiv->state), | 246 | otg_state_string(musb->xceiv->state), |
244 | jiffies_to_msecs(timeout - jiffies)); | 247 | jiffies_to_msecs(timeout - jiffies)); |
245 | mod_timer(&glue->timer, timeout); | 248 | mod_timer(&glue->timer[pdev->id], timeout); |
246 | } | 249 | } |
247 | 250 | ||
248 | static irqreturn_t dsps_interrupt(int irq, void *hci) | 251 | static irqreturn_t dsps_interrupt(int irq, void *hci) |
@@ -250,8 +253,8 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) | |||
250 | struct musb *musb = hci; | 253 | struct musb *musb = hci; |
251 | void __iomem *reg_base = musb->ctrl_base; | 254 | void __iomem *reg_base = musb->ctrl_base; |
252 | struct device *dev = musb->controller; | 255 | struct device *dev = musb->controller; |
253 | struct platform_device *pdev = to_platform_device(dev->parent); | 256 | struct platform_device *pdev = to_platform_device(dev); |
254 | struct dsps_glue *glue = platform_get_drvdata(pdev); | 257 | struct dsps_glue *glue = dev_get_drvdata(dev->parent); |
255 | const struct dsps_musb_wrapper *wrp = glue->wrp; | 258 | const struct dsps_musb_wrapper *wrp = glue->wrp; |
256 | unsigned long flags; | 259 | unsigned long flags; |
257 | irqreturn_t ret = IRQ_NONE; | 260 | irqreturn_t ret = IRQ_NONE; |
@@ -310,7 +313,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) | |||
310 | */ | 313 | */ |
311 | musb->int_usb &= ~MUSB_INTR_VBUSERROR; | 314 | musb->int_usb &= ~MUSB_INTR_VBUSERROR; |
312 | musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; | 315 | musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; |
313 | mod_timer(&glue->timer, | 316 | mod_timer(&glue->timer[pdev->id], |
314 | jiffies + wrp->poll_seconds * HZ); | 317 | jiffies + wrp->poll_seconds * HZ); |
315 | WARNING("VBUS error workaround (delay coming)\n"); | 318 | WARNING("VBUS error workaround (delay coming)\n"); |
316 | } else if (drvvbus) { | 319 | } else if (drvvbus) { |
@@ -318,7 +321,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) | |||
318 | MUSB_HST_MODE(musb); | 321 | MUSB_HST_MODE(musb); |
319 | musb->xceiv->otg->default_a = 1; | 322 | musb->xceiv->otg->default_a = 1; |
320 | musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; | 323 | musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; |
321 | del_timer(&glue->timer); | 324 | del_timer(&glue->timer[pdev->id]); |
322 | } else { | 325 | } else { |
323 | musb->is_active = 0; | 326 | musb->is_active = 0; |
324 | MUSB_DEV_MODE(musb); | 327 | MUSB_DEV_MODE(musb); |
@@ -345,7 +348,8 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) | |||
345 | 348 | ||
346 | /* Poll for ID change */ | 349 | /* Poll for ID change */ |
347 | if (musb->xceiv->state == OTG_STATE_B_IDLE) | 350 | if (musb->xceiv->state == OTG_STATE_B_IDLE) |
348 | mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); | 351 | mod_timer(&glue->timer[pdev->id], |
352 | jiffies + wrp->poll_seconds * HZ); | ||
349 | 353 | ||
350 | spin_unlock_irqrestore(&musb->lock, flags); | 354 | spin_unlock_irqrestore(&musb->lock, flags); |
351 | 355 | ||
@@ -356,8 +360,8 @@ static int dsps_musb_init(struct musb *musb) | |||
356 | { | 360 | { |
357 | struct device *dev = musb->controller; | 361 | struct device *dev = musb->controller; |
358 | struct musb_hdrc_platform_data *plat = dev->platform_data; | 362 | struct musb_hdrc_platform_data *plat = dev->platform_data; |
359 | struct platform_device *pdev = to_platform_device(dev->parent); | 363 | struct platform_device *pdev = to_platform_device(dev); |
360 | struct dsps_glue *glue = platform_get_drvdata(pdev); | 364 | struct dsps_glue *glue = dev_get_drvdata(dev->parent); |
361 | const struct dsps_musb_wrapper *wrp = glue->wrp; | 365 | const struct dsps_musb_wrapper *wrp = glue->wrp; |
362 | struct omap_musb_board_data *data = plat->board_data; | 366 | struct omap_musb_board_data *data = plat->board_data; |
363 | void __iomem *reg_base = musb->ctrl_base; | 367 | void __iomem *reg_base = musb->ctrl_base; |
@@ -380,7 +384,7 @@ static int dsps_musb_init(struct musb *musb) | |||
380 | goto err0; | 384 | goto err0; |
381 | } | 385 | } |
382 | 386 | ||
383 | setup_timer(&glue->timer, otg_timer, (unsigned long) musb); | 387 | setup_timer(&glue->timer[pdev->id], otg_timer, (unsigned long) musb); |
384 | 388 | ||
385 | /* Reset the musb */ | 389 | /* Reset the musb */ |
386 | dsps_writel(reg_base, wrp->control, (1 << wrp->reset)); | 390 | dsps_writel(reg_base, wrp->control, (1 << wrp->reset)); |
@@ -411,10 +415,10 @@ static int dsps_musb_exit(struct musb *musb) | |||
411 | struct device *dev = musb->controller; | 415 | struct device *dev = musb->controller; |
412 | struct musb_hdrc_platform_data *plat = dev->platform_data; | 416 | struct musb_hdrc_platform_data *plat = dev->platform_data; |
413 | struct omap_musb_board_data *data = plat->board_data; | 417 | struct omap_musb_board_data *data = plat->board_data; |
414 | struct platform_device *pdev = to_platform_device(dev->parent); | 418 | struct platform_device *pdev = to_platform_device(dev); |
415 | struct dsps_glue *glue = platform_get_drvdata(pdev); | 419 | struct dsps_glue *glue = dev_get_drvdata(dev->parent); |
416 | 420 | ||
417 | del_timer_sync(&glue->timer); | 421 | del_timer_sync(&glue->timer[pdev->id]); |
418 | 422 | ||
419 | /* Shutdown the on-chip PHY and its PLL. */ | 423 | /* Shutdown the on-chip PHY and its PLL. */ |
420 | if (data->set_phy_power) | 424 | if (data->set_phy_power) |
@@ -493,7 +497,7 @@ static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id) | |||
493 | musb->dev.dma_mask = &musb_dmamask; | 497 | musb->dev.dma_mask = &musb_dmamask; |
494 | musb->dev.coherent_dma_mask = musb_dmamask; | 498 | musb->dev.coherent_dma_mask = musb_dmamask; |
495 | 499 | ||
496 | glue->musb = musb; | 500 | glue->musb[id] = musb; |
497 | 501 | ||
498 | pdata->platform_ops = &dsps_ops; | 502 | pdata->platform_ops = &dsps_ops; |
499 | 503 | ||
@@ -525,11 +529,11 @@ err0: | |||
525 | return ret; | 529 | return ret; |
526 | } | 530 | } |
527 | 531 | ||
528 | static void __devexit dsps_delete_musb_pdev(struct dsps_glue *glue) | 532 | static void dsps_delete_musb_pdev(struct dsps_glue *glue, u8 id) |
529 | { | 533 | { |
530 | musb_put_id(glue->dev, glue->musb->id); | 534 | musb_put_id(glue->dev, glue->musb[id]->id); |
531 | platform_device_del(glue->musb); | 535 | platform_device_del(glue->musb[id]); |
532 | platform_device_put(glue->musb); | 536 | platform_device_put(glue->musb[id]); |
533 | } | 537 | } |
534 | 538 | ||
535 | static int __devinit dsps_probe(struct platform_device *pdev) | 539 | static int __devinit dsps_probe(struct platform_device *pdev) |
@@ -539,7 +543,7 @@ static int __devinit dsps_probe(struct platform_device *pdev) | |||
539 | (struct dsps_musb_wrapper *)id->driver_data; | 543 | (struct dsps_musb_wrapper *)id->driver_data; |
540 | struct dsps_glue *glue; | 544 | struct dsps_glue *glue; |
541 | struct resource *iomem; | 545 | struct resource *iomem; |
542 | int ret; | 546 | int ret, i; |
543 | 547 | ||
544 | /* allocate glue */ | 548 | /* allocate glue */ |
545 | glue = kzalloc(sizeof(*glue), GFP_KERNEL); | 549 | glue = kzalloc(sizeof(*glue), GFP_KERNEL); |
@@ -580,7 +584,16 @@ static int __devinit dsps_probe(struct platform_device *pdev) | |||
580 | ret = pm_runtime_get_sync(&pdev->dev); | 584 | ret = pm_runtime_get_sync(&pdev->dev); |
581 | if (ret < 0) { | 585 | if (ret < 0) { |
582 | dev_err(&pdev->dev, "pm_runtime_get_sync FAILED"); | 586 | dev_err(&pdev->dev, "pm_runtime_get_sync FAILED"); |
583 | goto err3; | 587 | /* create the child platform device for all instances of musb */ |
588 | for (i = 0; i < wrp->instances ; i++) { | ||
589 | ret = dsps_create_musb_pdev(glue, i); | ||
590 | if (ret != 0) { | ||
591 | dev_err(&pdev->dev, "failed to create child pdev\n"); | ||
592 | /* release resources of previously created instances */ | ||
593 | for (i--; i >= 0 ; i--) | ||
594 | dsps_delete_musb_pdev(glue, i); | ||
595 | goto err3; | ||
596 | } | ||
584 | } | 597 | } |
585 | 598 | ||
586 | return 0; | 599 | return 0; |
@@ -597,9 +610,12 @@ err0: | |||
597 | static int __devexit dsps_remove(struct platform_device *pdev) | 610 | static int __devexit dsps_remove(struct platform_device *pdev) |
598 | { | 611 | { |
599 | struct dsps_glue *glue = platform_get_drvdata(pdev); | 612 | struct dsps_glue *glue = platform_get_drvdata(pdev); |
613 | const struct dsps_musb_wrapper *wrp = glue->wrp; | ||
614 | int i; | ||
600 | 615 | ||
601 | /* delete the child platform device */ | 616 | /* delete the child platform device */ |
602 | dsps_delete_musb_pdev(glue); | 617 | for (i = 0; i < wrp->instances ; i++) |
618 | dsps_delete_musb_pdev(glue, i); | ||
603 | 619 | ||
604 | /* disable usbss clocks */ | 620 | /* disable usbss clocks */ |
605 | pm_runtime_put(&pdev->dev); | 621 | pm_runtime_put(&pdev->dev); |
@@ -665,6 +681,7 @@ static const struct dsps_musb_wrapper ti81xx_driver_data __devinitconst = { | |||
665 | .rxep_bitmap = (0xfffe << 16), | 681 | .rxep_bitmap = (0xfffe << 16), |
666 | .musb_core_offset = 0x400, | 682 | .musb_core_offset = 0x400, |
667 | .poll_seconds = 2, | 683 | .poll_seconds = 2, |
684 | .instances = 2, | ||
668 | }; | 685 | }; |
669 | 686 | ||
670 | static const struct platform_device_id musb_dsps_id_table[] __devinitconst = { | 687 | static const struct platform_device_id musb_dsps_id_table[] __devinitconst = { |