staging: dwc2: add check on dwc2_core_reset return
authorJulien DELACOU <julien.delacou@st.com>
Wed, 20 Nov 2013 16:29:49 +0000 (17:29 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 25 Nov 2013 19:57:53 +0000 (11:57 -0800)
If the GRSTCTL_CSFTRST self-clearing bit never comes
back to 0 for any reason, the controller is under reset
state and cannot be used. It's preferable to abort
initialization in such case.

Signed-off-by: Julien Delacou <julien.delacou@st.com>
Acked-by: Paul Zimmerman <paulz@synopsys.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/dwc2/core.c

index e4249404958a7d99063edad2e8725ec6bb645b22..53d540864cf0021cee08ce47ea2557ba0906091c 100644 (file)
@@ -114,7 +114,7 @@ static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg)
  * Do core a soft reset of the core.  Be careful with this because it
  * resets all the internal state machines of the core.
  */
-static void dwc2_core_reset(struct dwc2_hsotg *hsotg)
+static int dwc2_core_reset(struct dwc2_hsotg *hsotg)
 {
        u32 greset;
        int count = 0;
@@ -129,7 +129,7 @@ static void dwc2_core_reset(struct dwc2_hsotg *hsotg)
                        dev_warn(hsotg->dev,
                                 "%s() HANG! AHB Idle GRSTCTL=%0x\n",
                                 __func__, greset);
-                       return;
+                       return -EBUSY;
                }
        } while (!(greset & GRSTCTL_AHBIDLE));
 
@@ -144,7 +144,7 @@ static void dwc2_core_reset(struct dwc2_hsotg *hsotg)
                        dev_warn(hsotg->dev,
                                 "%s() HANG! Soft Reset GRSTCTL=%0x\n",
                                 __func__, greset);
-                       break;
+                       return -EBUSY;
                }
        } while (greset & GRSTCTL_CSFTRST);
 
@@ -153,11 +153,14 @@ static void dwc2_core_reset(struct dwc2_hsotg *hsotg)
         * not stay in host mode after a connector ID change!
         */
        usleep_range(150000, 200000);
+
+       return 0;
 }
 
-static void dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
+static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
 {
        u32 usbcfg, i2cctl;
+       int retval = 0;
 
        /*
         * core_init() is now called on every switch so only call the
@@ -170,7 +173,12 @@ static void dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
                writel(usbcfg, hsotg->regs + GUSBCFG);
 
                /* Reset after a PHY select */
-               dwc2_core_reset(hsotg);
+               retval = dwc2_core_reset(hsotg);
+               if (retval) {
+                       dev_err(hsotg->dev, "%s() Reset failed, aborting",
+                                       __func__);
+                       return retval;
+               }
        }
 
        /*
@@ -198,14 +206,17 @@ static void dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
                i2cctl |= GI2CCTL_I2CEN;
                writel(i2cctl, hsotg->regs + GI2CCTL);
        }
+
+       return retval;
 }
 
-static void dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
+static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
 {
        u32 usbcfg;
+       int retval = 0;
 
        if (!select_phy)
-               return;
+               return -ENODEV;
 
        usbcfg = readl(hsotg->regs + GUSBCFG);
 
@@ -238,20 +249,32 @@ static void dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
        writel(usbcfg, hsotg->regs + GUSBCFG);
 
        /* Reset after setting the PHY parameters */
-       dwc2_core_reset(hsotg);
+       retval = dwc2_core_reset(hsotg);
+       if (retval) {
+               dev_err(hsotg->dev, "%s() Reset failed, aborting",
+                               __func__);
+               return retval;
+       }
+
+       return retval;
 }
 
-static void dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
+static int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
 {
        u32 usbcfg;
+       int retval = 0;
 
        if (hsotg->core_params->speed == DWC2_SPEED_PARAM_FULL &&
            hsotg->core_params->phy_type == DWC2_PHY_TYPE_PARAM_FS) {
                /* If FS mode with FS PHY */
-               dwc2_fs_phy_init(hsotg, select_phy);
+               retval = dwc2_fs_phy_init(hsotg, select_phy);
+               if (retval)
+                       return retval;
        } else {
                /* High speed PHY */
-               dwc2_hs_phy_init(hsotg, select_phy);
+               retval = dwc2_hs_phy_init(hsotg, select_phy);
+               if (retval)
+                       return retval;
        }
 
        if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
@@ -268,6 +291,8 @@ static void dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
                usbcfg &= ~GUSBCFG_ULPI_CLK_SUSP_M;
                writel(usbcfg, hsotg->regs + GUSBCFG);
        }
+
+       return retval;
 }
 
 static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg)
@@ -382,12 +407,19 @@ int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq)
        writel(usbcfg, hsotg->regs + GUSBCFG);
 
        /* Reset the Controller */
-       dwc2_core_reset(hsotg);
+       retval = dwc2_core_reset(hsotg);
+       if (retval) {
+               dev_err(hsotg->dev, "%s(): Reset failed, aborting\n",
+                               __func__);
+               return retval;
+       }
 
        /*
         * This needs to happen in FS mode before any other programming occurs
         */
-       dwc2_phy_init(hsotg, select_phy);
+       retval = dwc2_phy_init(hsotg, select_phy);
+       if (retval)
+               return retval;
 
        /* Program the GAHBCFG Register */
        retval = dwc2_gahbcfg_init(hsotg);