|
@@ -144,6 +144,7 @@ struct dsps_glue {
|
|
|
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;
|
|
@@ -477,6 +478,19 @@ static int dsps_musb_init(struct musb *musb)
|
|
|
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;
|
|
@@ -544,19 +558,82 @@ static int dsps_musb_set_mode(struct musb *musb, u8 mode)
|
|
|
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 = {
|