const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
struct timer_list timer; /* otg_workaround timer */
unsigned long last_timer; /* last timer data for each instance */
+ bool sw_babble_enabled;
struct dsps_context context;
struct debugfs_regset32 regset;
val &= ~(1 << wrp->otg_disable);
dsps_writel(musb->ctrl_base, wrp->phy_utmi, val);
+ /*
+ * Check whether the dsps version has babble control enabled.
+ * In latest silicon revision the babble control logic is enabled.
+ * If MUSB_BABBLE_CTL returns 0x4 then we have the babble control
+ * logic enabled.
+ */
+ val = dsps_readb(musb->mregs, MUSB_BABBLE_CTL);
+ if (val == MUSB_BABBLE_RCV_DISABLE) {
+ glue->sw_babble_enabled = true;
+ val |= MUSB_BABBLE_SW_SESSION_CTRL;
+ dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, val);
+ }
+
ret = dsps_musb_dbg_init(musb, glue);
if (ret)
return ret;
return 0;
}
+static bool sw_babble_control(struct musb *musb)
+{
+ u8 babble_ctl;
+ bool session_restart = false;
+
+ babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL);
+ dev_dbg(musb->controller, "babble: MUSB_BABBLE_CTL value %x\n",
+ babble_ctl);
+ /*
+ * check line monitor flag to check whether babble is
+ * due to noise
+ */
+ dev_dbg(musb->controller, "STUCK_J is %s\n",
+ babble_ctl & MUSB_BABBLE_STUCK_J ? "set" : "reset");
+
+ if (babble_ctl & MUSB_BABBLE_STUCK_J) {
+ int timeout = 10;
+
+ /*
+ * babble is due to noise, then set transmit idle (d7 bit)
+ * to resume normal operation
+ */
+ babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL);
+ babble_ctl |= MUSB_BABBLE_FORCE_TXIDLE;
+ dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, babble_ctl);
+
+ /* wait till line monitor flag cleared */
+ dev_dbg(musb->controller, "Set TXIDLE, wait J to clear\n");
+ do {
+ babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL);
+ udelay(1);
+ } while ((babble_ctl & MUSB_BABBLE_STUCK_J) && timeout--);
+
+ /* check whether stuck_at_j bit cleared */
+ if (babble_ctl & MUSB_BABBLE_STUCK_J) {
+ /*
+ * real babble condition has occurred
+ * restart the controller to start the
+ * session again
+ */
+ dev_dbg(musb->controller, "J not cleared, misc (%x)\n",
+ babble_ctl);
+ session_restart = true;
+ }
+ } else {
+ session_restart = true;
+ }
+
+ return session_restart;
+}
+
static int dsps_musb_reset(struct musb *musb)
{
struct device *dev = musb->controller;
struct dsps_glue *glue = dev_get_drvdata(dev->parent);
const struct dsps_musb_wrapper *wrp = glue->wrp;
+ int session_restart = 0;
- dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset));
- usleep_range(100, 200);
- usb_phy_shutdown(musb->xceiv);
- usleep_range(100, 200);
- usb_phy_init(musb->xceiv);
+ if (glue->sw_babble_enabled)
+ session_restart = sw_babble_control(musb);
+ /*
+ * In case of new silicon version babble condition can be recovered
+ * without resetting the MUSB. But for older silicon versions, MUSB
+ * reset is needed
+ */
+ if (session_restart || !glue->sw_babble_enabled) {
+ dev_info(musb->controller, "Restarting MUSB to recover from Babble\n");
+ dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset));
+ usleep_range(100, 200);
+ usb_phy_shutdown(musb->xceiv);
+ usleep_range(100, 200);
+ usb_phy_init(musb->xceiv);
+ session_restart = 1;
+ }
- return 0;
+ return !session_restart;
}
static struct musb_platform_ops dsps_ops = {