diff options
Diffstat (limited to 'drivers/usb/musb/da8xx.c')
-rw-r--r-- | drivers/usb/musb/da8xx.c | 170 |
1 files changed, 153 insertions, 17 deletions
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 84427bebbf62..69a0da3c8f09 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/clk.h> | 30 | #include <linux/clk.h> |
31 | #include <linux/io.h> | 31 | #include <linux/io.h> |
32 | #include <linux/platform_device.h> | ||
33 | #include <linux/dma-mapping.h> | ||
32 | 34 | ||
33 | #include <mach/da8xx.h> | 35 | #include <mach/da8xx.h> |
34 | #include <mach/usb.h> | 36 | #include <mach/usb.h> |
@@ -78,6 +80,12 @@ | |||
78 | 80 | ||
79 | #define CFGCHIP2 IO_ADDRESS(DA8XX_SYSCFG0_BASE + DA8XX_CFGCHIP2_REG) | 81 | #define CFGCHIP2 IO_ADDRESS(DA8XX_SYSCFG0_BASE + DA8XX_CFGCHIP2_REG) |
80 | 82 | ||
83 | struct da8xx_glue { | ||
84 | struct device *dev; | ||
85 | struct platform_device *musb; | ||
86 | struct clk *clk; | ||
87 | }; | ||
88 | |||
81 | /* | 89 | /* |
82 | * REVISIT (PM): we should be able to keep the PHY in low power mode most | 90 | * REVISIT (PM): we should be able to keep the PHY in low power mode most |
83 | * of the time (24 MHz oscillator and PLL off, etc.) by setting POWER.D0 | 91 | * of the time (24 MHz oscillator and PLL off, etc.) by setting POWER.D0 |
@@ -131,9 +139,9 @@ static inline void phy_off(void) | |||
131 | */ | 139 | */ |
132 | 140 | ||
133 | /** | 141 | /** |
134 | * musb_platform_enable - enable interrupts | 142 | * da8xx_musb_enable - enable interrupts |
135 | */ | 143 | */ |
136 | void musb_platform_enable(struct musb *musb) | 144 | static void da8xx_musb_enable(struct musb *musb) |
137 | { | 145 | { |
138 | void __iomem *reg_base = musb->ctrl_base; | 146 | void __iomem *reg_base = musb->ctrl_base; |
139 | u32 mask; | 147 | u32 mask; |
@@ -151,9 +159,9 @@ void musb_platform_enable(struct musb *musb) | |||
151 | } | 159 | } |
152 | 160 | ||
153 | /** | 161 | /** |
154 | * musb_platform_disable - disable HDRC and flush interrupts | 162 | * da8xx_musb_disable - disable HDRC and flush interrupts |
155 | */ | 163 | */ |
156 | void musb_platform_disable(struct musb *musb) | 164 | static void da8xx_musb_disable(struct musb *musb) |
157 | { | 165 | { |
158 | void __iomem *reg_base = musb->ctrl_base; | 166 | void __iomem *reg_base = musb->ctrl_base; |
159 | 167 | ||
@@ -170,7 +178,7 @@ void musb_platform_disable(struct musb *musb) | |||
170 | #define portstate(stmt) | 178 | #define portstate(stmt) |
171 | #endif | 179 | #endif |
172 | 180 | ||
173 | static void da8xx_set_vbus(struct musb *musb, int is_on) | 181 | static void da8xx_musb_set_vbus(struct musb *musb, int is_on) |
174 | { | 182 | { |
175 | WARN_ON(is_on && is_peripheral_active(musb)); | 183 | WARN_ON(is_on && is_peripheral_active(musb)); |
176 | } | 184 | } |
@@ -252,7 +260,7 @@ static void otg_timer(unsigned long _musb) | |||
252 | spin_unlock_irqrestore(&musb->lock, flags); | 260 | spin_unlock_irqrestore(&musb->lock, flags); |
253 | } | 261 | } |
254 | 262 | ||
255 | void musb_platform_try_idle(struct musb *musb, unsigned long timeout) | 263 | static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout) |
256 | { | 264 | { |
257 | static unsigned long last_timer; | 265 | static unsigned long last_timer; |
258 | 266 | ||
@@ -282,7 +290,7 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout) | |||
282 | mod_timer(&otg_workaround, timeout); | 290 | mod_timer(&otg_workaround, timeout); |
283 | } | 291 | } |
284 | 292 | ||
285 | static irqreturn_t da8xx_interrupt(int irq, void *hci) | 293 | static irqreturn_t da8xx_musb_interrupt(int irq, void *hci) |
286 | { | 294 | { |
287 | struct musb *musb = hci; | 295 | struct musb *musb = hci; |
288 | void __iomem *reg_base = musb->ctrl_base; | 296 | void __iomem *reg_base = musb->ctrl_base; |
@@ -380,7 +388,7 @@ static irqreturn_t da8xx_interrupt(int irq, void *hci) | |||
380 | return ret; | 388 | return ret; |
381 | } | 389 | } |
382 | 390 | ||
383 | int musb_platform_set_mode(struct musb *musb, u8 musb_mode) | 391 | static int da8xx_musb_set_mode(struct musb *musb, u8 musb_mode) |
384 | { | 392 | { |
385 | u32 cfgchip2 = __raw_readl(CFGCHIP2); | 393 | u32 cfgchip2 = __raw_readl(CFGCHIP2); |
386 | 394 | ||
@@ -409,15 +417,13 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode) | |||
409 | return 0; | 417 | return 0; |
410 | } | 418 | } |
411 | 419 | ||
412 | int __init musb_platform_init(struct musb *musb, void *board_data) | 420 | static int da8xx_musb_init(struct musb *musb) |
413 | { | 421 | { |
414 | void __iomem *reg_base = musb->ctrl_base; | 422 | void __iomem *reg_base = musb->ctrl_base; |
415 | u32 rev; | 423 | u32 rev; |
416 | 424 | ||
417 | musb->mregs += DA8XX_MENTOR_CORE_OFFSET; | 425 | musb->mregs += DA8XX_MENTOR_CORE_OFFSET; |
418 | 426 | ||
419 | clk_enable(musb->clock); | ||
420 | |||
421 | /* Returns zero if e.g. not clocked */ | 427 | /* Returns zero if e.g. not clocked */ |
422 | rev = musb_readl(reg_base, DA8XX_USB_REVISION_REG); | 428 | rev = musb_readl(reg_base, DA8XX_USB_REVISION_REG); |
423 | if (!rev) | 429 | if (!rev) |
@@ -431,8 +437,6 @@ int __init musb_platform_init(struct musb *musb, void *board_data) | |||
431 | if (is_host_enabled(musb)) | 437 | if (is_host_enabled(musb)) |
432 | setup_timer(&otg_workaround, otg_timer, (unsigned long)musb); | 438 | setup_timer(&otg_workaround, otg_timer, (unsigned long)musb); |
433 | 439 | ||
434 | musb->board_set_vbus = da8xx_set_vbus; | ||
435 | |||
436 | /* Reset the controller */ | 440 | /* Reset the controller */ |
437 | musb_writel(reg_base, DA8XX_USB_CTRL_REG, DA8XX_SOFT_RESET_MASK); | 441 | musb_writel(reg_base, DA8XX_USB_CTRL_REG, DA8XX_SOFT_RESET_MASK); |
438 | 442 | ||
@@ -446,14 +450,13 @@ int __init musb_platform_init(struct musb *musb, void *board_data) | |||
446 | rev, __raw_readl(CFGCHIP2), | 450 | rev, __raw_readl(CFGCHIP2), |
447 | musb_readb(reg_base, DA8XX_USB_CTRL_REG)); | 451 | musb_readb(reg_base, DA8XX_USB_CTRL_REG)); |
448 | 452 | ||
449 | musb->isr = da8xx_interrupt; | 453 | musb->isr = da8xx_musb_interrupt; |
450 | return 0; | 454 | return 0; |
451 | fail: | 455 | fail: |
452 | clk_disable(musb->clock); | ||
453 | return -ENODEV; | 456 | return -ENODEV; |
454 | } | 457 | } |
455 | 458 | ||
456 | int musb_platform_exit(struct musb *musb) | 459 | static int da8xx_musb_exit(struct musb *musb) |
457 | { | 460 | { |
458 | if (is_host_enabled(musb)) | 461 | if (is_host_enabled(musb)) |
459 | del_timer_sync(&otg_workaround); | 462 | del_timer_sync(&otg_workaround); |
@@ -463,7 +466,140 @@ int musb_platform_exit(struct musb *musb) | |||
463 | otg_put_transceiver(musb->xceiv); | 466 | otg_put_transceiver(musb->xceiv); |
464 | usb_nop_xceiv_unregister(); | 467 | usb_nop_xceiv_unregister(); |
465 | 468 | ||
466 | clk_disable(musb->clock); | 469 | return 0; |
470 | } | ||
471 | |||
472 | static const struct musb_platform_ops da8xx_ops = { | ||
473 | .init = da8xx_musb_init, | ||
474 | .exit = da8xx_musb_exit, | ||
475 | |||
476 | .enable = da8xx_musb_enable, | ||
477 | .disable = da8xx_musb_disable, | ||
478 | |||
479 | .set_mode = da8xx_musb_set_mode, | ||
480 | .try_idle = da8xx_musb_try_idle, | ||
481 | |||
482 | .set_vbus = da8xx_musb_set_vbus, | ||
483 | }; | ||
484 | |||
485 | static u64 da8xx_dmamask = DMA_BIT_MASK(32); | ||
486 | |||
487 | static int __init da8xx_probe(struct platform_device *pdev) | ||
488 | { | ||
489 | struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; | ||
490 | struct platform_device *musb; | ||
491 | struct da8xx_glue *glue; | ||
492 | |||
493 | struct clk *clk; | ||
494 | |||
495 | int ret = -ENOMEM; | ||
496 | |||
497 | glue = kzalloc(sizeof(*glue), GFP_KERNEL); | ||
498 | if (!glue) { | ||
499 | dev_err(&pdev->dev, "failed to allocate glue context\n"); | ||
500 | goto err0; | ||
501 | } | ||
502 | |||
503 | musb = platform_device_alloc("musb-hdrc", -1); | ||
504 | if (!musb) { | ||
505 | dev_err(&pdev->dev, "failed to allocate musb device\n"); | ||
506 | goto err1; | ||
507 | } | ||
508 | |||
509 | clk = clk_get(&pdev->dev, "usb20"); | ||
510 | if (IS_ERR(clk)) { | ||
511 | dev_err(&pdev->dev, "failed to get clock\n"); | ||
512 | ret = PTR_ERR(clk); | ||
513 | goto err2; | ||
514 | } | ||
515 | |||
516 | ret = clk_enable(clk); | ||
517 | if (ret) { | ||
518 | dev_err(&pdev->dev, "failed to enable clock\n"); | ||
519 | goto err3; | ||
520 | } | ||
521 | |||
522 | musb->dev.parent = &pdev->dev; | ||
523 | musb->dev.dma_mask = &da8xx_dmamask; | ||
524 | musb->dev.coherent_dma_mask = da8xx_dmamask; | ||
525 | |||
526 | glue->dev = &pdev->dev; | ||
527 | glue->musb = musb; | ||
528 | glue->clk = clk; | ||
529 | |||
530 | pdata->platform_ops = &da8xx_ops; | ||
531 | |||
532 | platform_set_drvdata(pdev, glue); | ||
533 | |||
534 | ret = platform_device_add_resources(musb, pdev->resource, | ||
535 | pdev->num_resources); | ||
536 | if (ret) { | ||
537 | dev_err(&pdev->dev, "failed to add resources\n"); | ||
538 | goto err4; | ||
539 | } | ||
540 | |||
541 | ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); | ||
542 | if (ret) { | ||
543 | dev_err(&pdev->dev, "failed to add platform_data\n"); | ||
544 | goto err4; | ||
545 | } | ||
546 | |||
547 | ret = platform_device_add(musb); | ||
548 | if (ret) { | ||
549 | dev_err(&pdev->dev, "failed to register musb device\n"); | ||
550 | goto err4; | ||
551 | } | ||
552 | |||
553 | return 0; | ||
554 | |||
555 | err4: | ||
556 | clk_disable(clk); | ||
557 | |||
558 | err3: | ||
559 | clk_put(clk); | ||
560 | |||
561 | err2: | ||
562 | platform_device_put(musb); | ||
563 | |||
564 | err1: | ||
565 | kfree(glue); | ||
566 | |||
567 | err0: | ||
568 | return ret; | ||
569 | } | ||
570 | |||
571 | static int __exit da8xx_remove(struct platform_device *pdev) | ||
572 | { | ||
573 | struct da8xx_glue *glue = platform_get_drvdata(pdev); | ||
574 | |||
575 | platform_device_del(glue->musb); | ||
576 | platform_device_put(glue->musb); | ||
577 | clk_disable(glue->clk); | ||
578 | clk_put(glue->clk); | ||
579 | kfree(glue); | ||
467 | 580 | ||
468 | return 0; | 581 | return 0; |
469 | } | 582 | } |
583 | |||
584 | static struct platform_driver da8xx_driver = { | ||
585 | .remove = __exit_p(da8xx_remove), | ||
586 | .driver = { | ||
587 | .name = "musb-da8xx", | ||
588 | }, | ||
589 | }; | ||
590 | |||
591 | MODULE_DESCRIPTION("DA8xx/OMAP-L1x MUSB Glue Layer"); | ||
592 | MODULE_AUTHOR("Sergei Shtylyov <sshtylyov@ru.mvista.com>"); | ||
593 | MODULE_LICENSE("GPL v2"); | ||
594 | |||
595 | static int __init da8xx_init(void) | ||
596 | { | ||
597 | return platform_driver_probe(&da8xx_driver, da8xx_probe); | ||
598 | } | ||
599 | subsys_initcall(da8xx_init); | ||
600 | |||
601 | static void __exit da8xx_exit(void) | ||
602 | { | ||
603 | platform_driver_unregister(&da8xx_driver); | ||
604 | } | ||
605 | module_exit(da8xx_exit); | ||