diff options
Diffstat (limited to 'drivers/usb/musb/musb_dsps.c')
-rw-r--r-- | drivers/usb/musb/musb_dsps.c | 118 |
1 files changed, 115 insertions, 3 deletions
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 1901f6fe5807..7a109eae9b9a 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c | |||
@@ -29,7 +29,6 @@ | |||
29 | * da8xx.c would be merged to this file after testing. | 29 | * da8xx.c would be merged to this file after testing. |
30 | */ | 30 | */ |
31 | 31 | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/io.h> | 32 | #include <linux/io.h> |
34 | #include <linux/err.h> | 33 | #include <linux/err.h> |
35 | #include <linux/platform_device.h> | 34 | #include <linux/platform_device.h> |
@@ -83,6 +82,8 @@ struct dsps_musb_wrapper { | |||
83 | u16 coreintr_status; | 82 | u16 coreintr_status; |
84 | u16 phy_utmi; | 83 | u16 phy_utmi; |
85 | u16 mode; | 84 | u16 mode; |
85 | u16 tx_mode; | ||
86 | u16 rx_mode; | ||
86 | 87 | ||
87 | /* bit positions for control */ | 88 | /* bit positions for control */ |
88 | unsigned reset:5; | 89 | unsigned reset:5; |
@@ -106,10 +107,24 @@ struct dsps_musb_wrapper { | |||
106 | 107 | ||
107 | /* bit positions for mode */ | 108 | /* bit positions for mode */ |
108 | unsigned iddig:5; | 109 | unsigned iddig:5; |
110 | unsigned iddig_mux:5; | ||
109 | /* miscellaneous stuff */ | 111 | /* miscellaneous stuff */ |
110 | u8 poll_seconds; | 112 | u8 poll_seconds; |
111 | }; | 113 | }; |
112 | 114 | ||
115 | /* | ||
116 | * register shadow for suspend | ||
117 | */ | ||
118 | struct dsps_context { | ||
119 | u32 control; | ||
120 | u32 epintr; | ||
121 | u32 coreintr; | ||
122 | u32 phy_utmi; | ||
123 | u32 mode; | ||
124 | u32 tx_mode; | ||
125 | u32 rx_mode; | ||
126 | }; | ||
127 | |||
113 | /** | 128 | /** |
114 | * DSPS glue structure. | 129 | * DSPS glue structure. |
115 | */ | 130 | */ |
@@ -119,6 +134,8 @@ struct dsps_glue { | |||
119 | const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ | 134 | const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ |
120 | struct timer_list timer; /* otg_workaround timer */ | 135 | struct timer_list timer; /* otg_workaround timer */ |
121 | unsigned long last_timer; /* last timer data for each instance */ | 136 | unsigned long last_timer; /* last timer data for each instance */ |
137 | |||
138 | struct dsps_context context; | ||
122 | }; | 139 | }; |
123 | 140 | ||
124 | static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) | 141 | static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) |
@@ -341,8 +358,9 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) | |||
341 | if (musb->int_tx || musb->int_rx || musb->int_usb) | 358 | if (musb->int_tx || musb->int_rx || musb->int_usb) |
342 | ret |= musb_interrupt(musb); | 359 | ret |= musb_interrupt(musb); |
343 | 360 | ||
344 | /* Poll for ID change */ | 361 | /* Poll for ID change in OTG port mode */ |
345 | if (musb->xceiv->state == OTG_STATE_B_IDLE) | 362 | if (musb->xceiv->state == OTG_STATE_B_IDLE && |
363 | musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) | ||
346 | mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); | 364 | mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); |
347 | out: | 365 | out: |
348 | spin_unlock_irqrestore(&musb->lock, flags); | 366 | spin_unlock_irqrestore(&musb->lock, flags); |
@@ -406,6 +424,54 @@ static int dsps_musb_exit(struct musb *musb) | |||
406 | return 0; | 424 | return 0; |
407 | } | 425 | } |
408 | 426 | ||
427 | static int dsps_musb_set_mode(struct musb *musb, u8 mode) | ||
428 | { | ||
429 | struct device *dev = musb->controller; | ||
430 | struct dsps_glue *glue = dev_get_drvdata(dev->parent); | ||
431 | const struct dsps_musb_wrapper *wrp = glue->wrp; | ||
432 | void __iomem *ctrl_base = musb->ctrl_base; | ||
433 | void __iomem *base = musb->mregs; | ||
434 | u32 reg; | ||
435 | |||
436 | reg = dsps_readl(base, wrp->mode); | ||
437 | |||
438 | switch (mode) { | ||
439 | case MUSB_HOST: | ||
440 | reg &= ~(1 << wrp->iddig); | ||
441 | |||
442 | /* | ||
443 | * if we're setting mode to host-only or device-only, we're | ||
444 | * going to ignore whatever the PHY sends us and just force | ||
445 | * ID pin status by SW | ||
446 | */ | ||
447 | reg |= (1 << wrp->iddig_mux); | ||
448 | |||
449 | dsps_writel(base, wrp->mode, reg); | ||
450 | dsps_writel(ctrl_base, wrp->phy_utmi, 0x02); | ||
451 | break; | ||
452 | case MUSB_PERIPHERAL: | ||
453 | reg |= (1 << wrp->iddig); | ||
454 | |||
455 | /* | ||
456 | * if we're setting mode to host-only or device-only, we're | ||
457 | * going to ignore whatever the PHY sends us and just force | ||
458 | * ID pin status by SW | ||
459 | */ | ||
460 | reg |= (1 << wrp->iddig_mux); | ||
461 | |||
462 | dsps_writel(base, wrp->mode, reg); | ||
463 | break; | ||
464 | case MUSB_OTG: | ||
465 | dsps_writel(base, wrp->phy_utmi, 0x02); | ||
466 | break; | ||
467 | default: | ||
468 | dev_err(glue->dev, "unsupported mode %d\n", mode); | ||
469 | return -EINVAL; | ||
470 | } | ||
471 | |||
472 | return 0; | ||
473 | } | ||
474 | |||
409 | static struct musb_platform_ops dsps_ops = { | 475 | static struct musb_platform_ops dsps_ops = { |
410 | .init = dsps_musb_init, | 476 | .init = dsps_musb_init, |
411 | .exit = dsps_musb_exit, | 477 | .exit = dsps_musb_exit, |
@@ -414,6 +480,7 @@ static struct musb_platform_ops dsps_ops = { | |||
414 | .disable = dsps_musb_disable, | 480 | .disable = dsps_musb_disable, |
415 | 481 | ||
416 | .try_idle = dsps_musb_try_idle, | 482 | .try_idle = dsps_musb_try_idle, |
483 | .set_mode = dsps_musb_set_mode, | ||
417 | }; | 484 | }; |
418 | 485 | ||
419 | static u64 musb_dmamask = DMA_BIT_MASK(32); | 486 | static u64 musb_dmamask = DMA_BIT_MASK(32); |
@@ -507,6 +574,7 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue, | |||
507 | 574 | ||
508 | config->num_eps = get_int_prop(dn, "mentor,num-eps"); | 575 | config->num_eps = get_int_prop(dn, "mentor,num-eps"); |
509 | config->ram_bits = get_int_prop(dn, "mentor,ram-bits"); | 576 | config->ram_bits = get_int_prop(dn, "mentor,ram-bits"); |
577 | config->host_port_deassert_reset_at_resume = 1; | ||
510 | pdata.mode = get_musb_port_mode(dev); | 578 | pdata.mode = get_musb_port_mode(dev); |
511 | /* DT keeps this entry in mA, musb expects it as per USB spec */ | 579 | /* DT keeps this entry in mA, musb expects it as per USB spec */ |
512 | pdata.power = get_int_prop(dn, "mentor,power") / 2; | 580 | pdata.power = get_int_prop(dn, "mentor,power") / 2; |
@@ -605,9 +673,12 @@ static const struct dsps_musb_wrapper am33xx_driver_data = { | |||
605 | .coreintr_status = 0x34, | 673 | .coreintr_status = 0x34, |
606 | .phy_utmi = 0xe0, | 674 | .phy_utmi = 0xe0, |
607 | .mode = 0xe8, | 675 | .mode = 0xe8, |
676 | .tx_mode = 0x70, | ||
677 | .rx_mode = 0x74, | ||
608 | .reset = 0, | 678 | .reset = 0, |
609 | .otg_disable = 21, | 679 | .otg_disable = 21, |
610 | .iddig = 8, | 680 | .iddig = 8, |
681 | .iddig_mux = 7, | ||
611 | .usb_shift = 0, | 682 | .usb_shift = 0, |
612 | .usb_mask = 0x1ff, | 683 | .usb_mask = 0x1ff, |
613 | .usb_bitmap = (0x1ff << 0), | 684 | .usb_bitmap = (0x1ff << 0), |
@@ -628,11 +699,52 @@ static const struct of_device_id musb_dsps_of_match[] = { | |||
628 | }; | 699 | }; |
629 | MODULE_DEVICE_TABLE(of, musb_dsps_of_match); | 700 | MODULE_DEVICE_TABLE(of, musb_dsps_of_match); |
630 | 701 | ||
702 | #ifdef CONFIG_PM | ||
703 | static int dsps_suspend(struct device *dev) | ||
704 | { | ||
705 | struct dsps_glue *glue = dev_get_drvdata(dev); | ||
706 | const struct dsps_musb_wrapper *wrp = glue->wrp; | ||
707 | struct musb *musb = platform_get_drvdata(glue->musb); | ||
708 | void __iomem *mbase = musb->ctrl_base; | ||
709 | |||
710 | glue->context.control = dsps_readl(mbase, wrp->control); | ||
711 | glue->context.epintr = dsps_readl(mbase, wrp->epintr_set); | ||
712 | glue->context.coreintr = dsps_readl(mbase, wrp->coreintr_set); | ||
713 | glue->context.phy_utmi = dsps_readl(mbase, wrp->phy_utmi); | ||
714 | glue->context.mode = dsps_readl(mbase, wrp->mode); | ||
715 | glue->context.tx_mode = dsps_readl(mbase, wrp->tx_mode); | ||
716 | glue->context.rx_mode = dsps_readl(mbase, wrp->rx_mode); | ||
717 | |||
718 | return 0; | ||
719 | } | ||
720 | |||
721 | static int dsps_resume(struct device *dev) | ||
722 | { | ||
723 | struct dsps_glue *glue = dev_get_drvdata(dev); | ||
724 | const struct dsps_musb_wrapper *wrp = glue->wrp; | ||
725 | struct musb *musb = platform_get_drvdata(glue->musb); | ||
726 | void __iomem *mbase = musb->ctrl_base; | ||
727 | |||
728 | dsps_writel(mbase, wrp->control, glue->context.control); | ||
729 | dsps_writel(mbase, wrp->epintr_set, glue->context.epintr); | ||
730 | dsps_writel(mbase, wrp->coreintr_set, glue->context.coreintr); | ||
731 | dsps_writel(mbase, wrp->phy_utmi, glue->context.phy_utmi); | ||
732 | dsps_writel(mbase, wrp->mode, glue->context.mode); | ||
733 | dsps_writel(mbase, wrp->tx_mode, glue->context.tx_mode); | ||
734 | dsps_writel(mbase, wrp->rx_mode, glue->context.rx_mode); | ||
735 | |||
736 | return 0; | ||
737 | } | ||
738 | #endif | ||
739 | |||
740 | static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume); | ||
741 | |||
631 | static struct platform_driver dsps_usbss_driver = { | 742 | static struct platform_driver dsps_usbss_driver = { |
632 | .probe = dsps_probe, | 743 | .probe = dsps_probe, |
633 | .remove = dsps_remove, | 744 | .remove = dsps_remove, |
634 | .driver = { | 745 | .driver = { |
635 | .name = "musb-dsps", | 746 | .name = "musb-dsps", |
747 | .pm = &dsps_pm_ops, | ||
636 | .of_match_table = musb_dsps_of_match, | 748 | .of_match_table = musb_dsps_of_match, |
637 | }, | 749 | }, |
638 | }; | 750 | }; |