diff options
Diffstat (limited to 'drivers/usb/musb/musb_dsps.c')
-rw-r--r-- | drivers/usb/musb/musb_dsps.c | 104 |
1 files changed, 97 insertions, 7 deletions
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 09529f94e72d..c791ba5da91a 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c | |||
@@ -56,16 +56,24 @@ static const struct of_device_id musb_dsps_of_match[]; | |||
56 | * dependent on musb core layer symbols. | 56 | * dependent on musb core layer symbols. |
57 | */ | 57 | */ |
58 | static inline u8 dsps_readb(const void __iomem *addr, unsigned offset) | 58 | static inline u8 dsps_readb(const void __iomem *addr, unsigned offset) |
59 | { return __raw_readb(addr + offset); } | 59 | { |
60 | return __raw_readb(addr + offset); | ||
61 | } | ||
60 | 62 | ||
61 | static inline u32 dsps_readl(const void __iomem *addr, unsigned offset) | 63 | static inline u32 dsps_readl(const void __iomem *addr, unsigned offset) |
62 | { return __raw_readl(addr + offset); } | 64 | { |
65 | return __raw_readl(addr + offset); | ||
66 | } | ||
63 | 67 | ||
64 | static inline void dsps_writeb(void __iomem *addr, unsigned offset, u8 data) | 68 | static inline void dsps_writeb(void __iomem *addr, unsigned offset, u8 data) |
65 | { __raw_writeb(data, addr + offset); } | 69 | { |
70 | __raw_writeb(data, addr + offset); | ||
71 | } | ||
66 | 72 | ||
67 | static inline void dsps_writel(void __iomem *addr, unsigned offset, u32 data) | 73 | static inline void dsps_writel(void __iomem *addr, unsigned offset, u32 data) |
68 | { __raw_writel(data, addr + offset); } | 74 | { |
75 | __raw_writel(data, addr + offset); | ||
76 | } | ||
69 | 77 | ||
70 | /** | 78 | /** |
71 | * DSPS musb wrapper register offset. | 79 | * DSPS musb wrapper register offset. |
@@ -136,6 +144,7 @@ struct dsps_glue { | |||
136 | const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ | 144 | const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ |
137 | struct timer_list timer; /* otg_workaround timer */ | 145 | struct timer_list timer; /* otg_workaround timer */ |
138 | unsigned long last_timer; /* last timer data for each instance */ | 146 | unsigned long last_timer; /* last timer data for each instance */ |
147 | bool sw_babble_enabled; | ||
139 | 148 | ||
140 | struct dsps_context context; | 149 | struct dsps_context context; |
141 | struct debugfs_regset32 regset; | 150 | struct debugfs_regset32 regset; |
@@ -469,6 +478,19 @@ static int dsps_musb_init(struct musb *musb) | |||
469 | val &= ~(1 << wrp->otg_disable); | 478 | val &= ~(1 << wrp->otg_disable); |
470 | dsps_writel(musb->ctrl_base, wrp->phy_utmi, val); | 479 | dsps_writel(musb->ctrl_base, wrp->phy_utmi, val); |
471 | 480 | ||
481 | /* | ||
482 | * Check whether the dsps version has babble control enabled. | ||
483 | * In latest silicon revision the babble control logic is enabled. | ||
484 | * If MUSB_BABBLE_CTL returns 0x4 then we have the babble control | ||
485 | * logic enabled. | ||
486 | */ | ||
487 | val = dsps_readb(musb->mregs, MUSB_BABBLE_CTL); | ||
488 | if (val == MUSB_BABBLE_RCV_DISABLE) { | ||
489 | glue->sw_babble_enabled = true; | ||
490 | val |= MUSB_BABBLE_SW_SESSION_CTRL; | ||
491 | dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, val); | ||
492 | } | ||
493 | |||
472 | ret = dsps_musb_dbg_init(musb, glue); | 494 | ret = dsps_musb_dbg_init(musb, glue); |
473 | if (ret) | 495 | if (ret) |
474 | return ret; | 496 | return ret; |
@@ -535,14 +557,82 @@ static int dsps_musb_set_mode(struct musb *musb, u8 mode) | |||
535 | return 0; | 557 | return 0; |
536 | } | 558 | } |
537 | 559 | ||
538 | static void dsps_musb_reset(struct musb *musb) | 560 | static bool sw_babble_control(struct musb *musb) |
561 | { | ||
562 | u8 babble_ctl; | ||
563 | bool session_restart = false; | ||
564 | |||
565 | babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL); | ||
566 | dev_dbg(musb->controller, "babble: MUSB_BABBLE_CTL value %x\n", | ||
567 | babble_ctl); | ||
568 | /* | ||
569 | * check line monitor flag to check whether babble is | ||
570 | * due to noise | ||
571 | */ | ||
572 | dev_dbg(musb->controller, "STUCK_J is %s\n", | ||
573 | babble_ctl & MUSB_BABBLE_STUCK_J ? "set" : "reset"); | ||
574 | |||
575 | if (babble_ctl & MUSB_BABBLE_STUCK_J) { | ||
576 | int timeout = 10; | ||
577 | |||
578 | /* | ||
579 | * babble is due to noise, then set transmit idle (d7 bit) | ||
580 | * to resume normal operation | ||
581 | */ | ||
582 | babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL); | ||
583 | babble_ctl |= MUSB_BABBLE_FORCE_TXIDLE; | ||
584 | dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, babble_ctl); | ||
585 | |||
586 | /* wait till line monitor flag cleared */ | ||
587 | dev_dbg(musb->controller, "Set TXIDLE, wait J to clear\n"); | ||
588 | do { | ||
589 | babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL); | ||
590 | udelay(1); | ||
591 | } while ((babble_ctl & MUSB_BABBLE_STUCK_J) && timeout--); | ||
592 | |||
593 | /* check whether stuck_at_j bit cleared */ | ||
594 | if (babble_ctl & MUSB_BABBLE_STUCK_J) { | ||
595 | /* | ||
596 | * real babble condition has occurred | ||
597 | * restart the controller to start the | ||
598 | * session again | ||
599 | */ | ||
600 | dev_dbg(musb->controller, "J not cleared, misc (%x)\n", | ||
601 | babble_ctl); | ||
602 | session_restart = true; | ||
603 | } | ||
604 | } else { | ||
605 | session_restart = true; | ||
606 | } | ||
607 | |||
608 | return session_restart; | ||
609 | } | ||
610 | |||
611 | static int dsps_musb_reset(struct musb *musb) | ||
539 | { | 612 | { |
540 | struct device *dev = musb->controller; | 613 | struct device *dev = musb->controller; |
541 | struct dsps_glue *glue = dev_get_drvdata(dev->parent); | 614 | struct dsps_glue *glue = dev_get_drvdata(dev->parent); |
542 | const struct dsps_musb_wrapper *wrp = glue->wrp; | 615 | const struct dsps_musb_wrapper *wrp = glue->wrp; |
616 | int session_restart = 0; | ||
617 | |||
618 | if (glue->sw_babble_enabled) | ||
619 | session_restart = sw_babble_control(musb); | ||
620 | /* | ||
621 | * In case of new silicon version babble condition can be recovered | ||
622 | * without resetting the MUSB. But for older silicon versions, MUSB | ||
623 | * reset is needed | ||
624 | */ | ||
625 | if (session_restart || !glue->sw_babble_enabled) { | ||
626 | dev_info(musb->controller, "Restarting MUSB to recover from Babble\n"); | ||
627 | dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset)); | ||
628 | usleep_range(100, 200); | ||
629 | usb_phy_shutdown(musb->xceiv); | ||
630 | usleep_range(100, 200); | ||
631 | usb_phy_init(musb->xceiv); | ||
632 | session_restart = 1; | ||
633 | } | ||
543 | 634 | ||
544 | dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset)); | 635 | return !session_restart; |
545 | udelay(100); | ||
546 | } | 636 | } |
547 | 637 | ||
548 | static struct musb_platform_ops dsps_ops = { | 638 | static struct musb_platform_ops dsps_ops = { |