Merge tag 'for-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux...
[deliverable/linux.git] / drivers / usb / musb / musb_core.c
index 96d71fa2ae85628c47d71573209f8d7585d71ba8..3789b08ef67b037781e278c41c0d4b2f2d33e5d9 100644 (file)
@@ -99,6 +99,7 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
+#include <linux/usb.h>
 
 #include "musb_core.h"
 
@@ -507,8 +508,7 @@ void musb_hnp_stop(struct musb *musb)
        musb->port1_status &= ~(USB_PORT_STAT_C_CONNECTION << 16);
 }
 
-static void musb_disable_interrupts(struct musb *musb);
-static void musb_generic_disable(struct musb *musb);
+static void musb_recover_from_babble(struct musb *musb);
 
 /*
  * Interrupt Service Routine to record USB "global" interrupts.
@@ -550,7 +550,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                                                (USB_PORT_STAT_C_SUSPEND << 16)
                                                | MUSB_PORT_STAT_RESUME;
                                musb->rh_timer = jiffies
-                                                + msecs_to_jiffies(20);
+                                       + msecs_to_jiffies(USB_RESUME_TIMEOUT);
                                musb->need_finish_resume = 1;
 
                                musb->xceiv->otg->state = OTG_STATE_A_HOST;
@@ -864,31 +864,18 @@ b_host:
        if (int_usb & MUSB_INTR_RESET) {
                handled = IRQ_HANDLED;
                if (devctl & MUSB_DEVCTL_HM) {
-                       u8 power = musb_readl(musb->mregs, MUSB_POWER);
-
                        /*
-                        * Looks like non-HS BABBLE can be ignored, but
-                        * HS BABBLE is an error condition.
-                        *
-                        * For HS the solution is to avoid babble in the first
-                        * place and fix what caused BABBLE.
-                        *
-                        * When HS BABBLE happens what we can depends on which
+                        * When BABBLE happens what we can depends on which
                         * platform MUSB is running, because some platforms
                         * implemented proprietary means for 'recovering' from
                         * Babble conditions. One such platform is AM335x. In
-                        * most cases, however, the only thing we can do is drop
-                        * the session.
+                        * most cases, however, the only thing we can do is
+                        * drop the session.
                         */
-                       if (power & MUSB_POWER_HSMODE) {
-                               dev_err(musb->controller, "Babble\n");
+                       dev_err(musb->controller, "Babble\n");
 
-                               if (is_host_active(musb)) {
-                                       musb_disable_interrupts(musb);
-                                       schedule_delayed_work(&musb->recover_work,
-                                                       usecs_to_jiffies(10));
-                               }
-                       }
+                       if (is_host_active(musb))
+                               musb_recover_from_babble(musb);
                } else {
                        dev_dbg(musb->controller, "BUS RESET as %s\n",
                                usb_otg_state_string(musb->xceiv->otg->state));
@@ -1831,35 +1818,44 @@ static void musb_irq_work(struct work_struct *data)
        }
 }
 
-/* Recover from babble interrupt conditions */
-static void musb_recover_work(struct work_struct *data)
+static void musb_recover_from_babble(struct musb *musb)
 {
-       struct musb *musb = container_of(data, struct musb, recover_work.work);
-       int status, ret;
+       int ret;
+       u8 devctl;
+
+       musb_disable_interrupts(musb);
 
-       ret  = musb_platform_reset(musb);
+       /*
+        * wait at least 320 cycles of 60MHz clock. That's 5.3us, we will give
+        * it some slack and wait for 10us.
+        */
+       udelay(10);
+
+       ret  = musb_platform_recover(musb);
        if (ret) {
                musb_enable_interrupts(musb);
                return;
        }
 
-       usb_phy_vbus_off(musb->xceiv);
-       usleep_range(100, 200);
+       /* drop session bit */
+       devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+       devctl &= ~MUSB_DEVCTL_SESSION;
+       musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
 
-       usb_phy_vbus_on(musb->xceiv);
-       usleep_range(100, 200);
+       /* tell usbcore about it */
+       musb_root_disconnect(musb);
 
        /*
         * When a babble condition occurs, the musb controller
         * removes the session bit and the endpoint config is lost.
         */
        if (musb->dyn_fifo)
-               status = ep_config_from_table(musb);
+               ret = ep_config_from_table(musb);
        else
-               status = ep_config_from_hw(musb);
+               ret = ep_config_from_hw(musb);
 
-       /* start the session again */
-       if (status == 0)
+       /* restart session */
+       if (ret == 0)
                musb_start(musb);
 }
 
@@ -2095,7 +2091,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
 
        /* Init IRQ workqueue before request_irq */
        INIT_WORK(&musb->irq_work, musb_irq_work);
-       INIT_DELAYED_WORK(&musb->recover_work, musb_recover_work);
        INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset);
        INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume);
 
@@ -2191,7 +2186,6 @@ fail4:
 
 fail3:
        cancel_work_sync(&musb->irq_work);
-       cancel_delayed_work_sync(&musb->recover_work);
        cancel_delayed_work_sync(&musb->finish_resume_work);
        cancel_delayed_work_sync(&musb->deassert_reset_work);
        if (musb->dma_controller)
@@ -2257,7 +2251,6 @@ static int musb_remove(struct platform_device *pdev)
                dma_controller_destroy(musb->dma_controller);
 
        cancel_work_sync(&musb->irq_work);
-       cancel_delayed_work_sync(&musb->recover_work);
        cancel_delayed_work_sync(&musb->finish_resume_work);
        cancel_delayed_work_sync(&musb->deassert_reset_work);
        musb_free(musb);
@@ -2471,7 +2464,7 @@ static int musb_resume(struct device *dev)
        if (musb->need_finish_resume) {
                musb->need_finish_resume = 0;
                schedule_delayed_work(&musb->finish_resume_work,
-                                     msecs_to_jiffies(20));
+                                     msecs_to_jiffies(USB_RESUME_TIMEOUT));
        }
 
        /*
@@ -2514,7 +2507,7 @@ static int musb_runtime_resume(struct device *dev)
        if (musb->need_finish_resume) {
                musb->need_finish_resume = 0;
                schedule_delayed_work(&musb->finish_resume_work,
-                               msecs_to_jiffies(20));
+                               msecs_to_jiffies(USB_RESUME_TIMEOUT));
        }
 
        return 0;
This page took 0.033273 seconds and 5 git commands to generate.