@@ -144,6 +144,7 @@ struct dsps_glue {
144144 const struct dsps_musb_wrapper * wrp ; /* wrapper register offsets */
145145 struct timer_list timer ; /* otg_workaround timer */
146146 unsigned long last_timer ; /* last timer data for each instance */
147+ bool sw_babble_enabled ;
147148
148149 struct dsps_context context ;
149150 struct debugfs_regset32 regset ;
@@ -477,6 +478,19 @@ static int dsps_musb_init(struct musb *musb)
477478 val &= ~(1 << wrp -> otg_disable );
478479 dsps_writel (musb -> ctrl_base , wrp -> phy_utmi , val );
479480
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+
480494 ret = dsps_musb_dbg_init (musb , glue );
481495 if (ret )
482496 return ret ;
@@ -544,19 +558,82 @@ static int dsps_musb_set_mode(struct musb *musb, u8 mode)
544558 return 0 ;
545559}
546560
561+ static bool sw_babble_control (struct musb * musb )
562+ {
563+ u8 babble_ctl ;
564+ bool session_restart = false;
565+
566+ babble_ctl = dsps_readb (musb -> mregs , MUSB_BABBLE_CTL );
567+ dev_dbg (musb -> controller , "babble: MUSB_BABBLE_CTL value %x\n" ,
568+ babble_ctl );
569+ /*
570+ * check line monitor flag to check whether babble is
571+ * due to noise
572+ */
573+ dev_dbg (musb -> controller , "STUCK_J is %s\n" ,
574+ babble_ctl & MUSB_BABBLE_STUCK_J ? "set" : "reset" );
575+
576+ if (babble_ctl & MUSB_BABBLE_STUCK_J ) {
577+ int timeout = 10 ;
578+
579+ /*
580+ * babble is due to noise, then set transmit idle (d7 bit)
581+ * to resume normal operation
582+ */
583+ babble_ctl = dsps_readb (musb -> mregs , MUSB_BABBLE_CTL );
584+ babble_ctl |= MUSB_BABBLE_FORCE_TXIDLE ;
585+ dsps_writeb (musb -> mregs , MUSB_BABBLE_CTL , babble_ctl );
586+
587+ /* wait till line monitor flag cleared */
588+ dev_dbg (musb -> controller , "Set TXIDLE, wait J to clear\n" );
589+ do {
590+ babble_ctl = dsps_readb (musb -> mregs , MUSB_BABBLE_CTL );
591+ udelay (1 );
592+ } while ((babble_ctl & MUSB_BABBLE_STUCK_J ) && timeout -- );
593+
594+ /* check whether stuck_at_j bit cleared */
595+ if (babble_ctl & MUSB_BABBLE_STUCK_J ) {
596+ /*
597+ * real babble condition has occurred
598+ * restart the controller to start the
599+ * session again
600+ */
601+ dev_dbg (musb -> controller , "J not cleared, misc (%x)\n" ,
602+ babble_ctl );
603+ session_restart = true;
604+ }
605+ } else {
606+ session_restart = true;
607+ }
608+
609+ return session_restart ;
610+ }
611+
547612static int dsps_musb_reset (struct musb * musb )
548613{
549614 struct device * dev = musb -> controller ;
550615 struct dsps_glue * glue = dev_get_drvdata (dev -> parent );
551616 const struct dsps_musb_wrapper * wrp = glue -> wrp ;
617+ int session_restart = 0 ;
552618
553- dsps_writel (musb -> ctrl_base , wrp -> control , (1 << wrp -> reset ));
554- usleep_range (100 , 200 );
555- usb_phy_shutdown (musb -> xceiv );
556- usleep_range (100 , 200 );
557- usb_phy_init (musb -> xceiv );
619+ if (glue -> sw_babble_enabled )
620+ session_restart = sw_babble_control (musb );
621+ /*
622+ * In case of new silicon version babble condition can be recovered
623+ * without resetting the MUSB. But for older silicon versions, MUSB
624+ * reset is needed
625+ */
626+ if (session_restart || !glue -> sw_babble_enabled ) {
627+ dev_info (musb -> controller , "Restarting MUSB to recover from Babble\n" );
628+ dsps_writel (musb -> ctrl_base , wrp -> control , (1 << wrp -> reset ));
629+ usleep_range (100 , 200 );
630+ usb_phy_shutdown (musb -> xceiv );
631+ usleep_range (100 , 200 );
632+ usb_phy_init (musb -> xceiv );
633+ session_restart = 1 ;
634+ }
558635
559- return 0 ;
636+ return ! session_restart ;
560637}
561638
562639static struct musb_platform_ops dsps_ops = {
0 commit comments