mfd: Fix omap usbhs crash when rmmoding ehci or ohci
authorKeshava Munegowda <Keshava_mgowda@ti.com>
Mon, 16 May 2011 08:54:58 +0000 (14:24 +0530)
committerSamuel Ortiz <sameo@linux.intel.com>
Thu, 26 May 2011 17:45:49 +0000 (19:45 +0200)
The disabling of clocks and freeing GPIO are changed
to fix the occurrence of the crash of rmmod of ehci and ohci
drivers. The GPIOs should be freed after the spin locks are
unlocked.

Signed-off-by: Keshava Munegowda <keshava_mgowda@ti.com>
Acked-by: Felipe Balbi <balbi@ti.com>
Cc: stable@kernel.org
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
drivers/mfd/omap-usb-host.c

index 3ab9ffa00aadf8c805477e2c323c2f1f889da2a8..55c5d4732f5f07d75da802d38a412f3215602d8c 100644 (file)
@@ -994,22 +994,33 @@ static void usbhs_disable(struct device *dev)
                        dev_dbg(dev, "operation timed out\n");
        }
 
-       if (pdata->ehci_data->phy_reset) {
-               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
-                       gpio_free(pdata->ehci_data->reset_gpio_port[0]);
-
-               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
-                       gpio_free(pdata->ehci_data->reset_gpio_port[1]);
+       if (is_omap_usbhs_rev2(omap)) {
+               if (is_ehci_tll_mode(pdata->port_mode[0]))
+                       clk_enable(omap->usbtll_p1_fck);
+               if (is_ehci_tll_mode(pdata->port_mode[1]))
+                       clk_enable(omap->usbtll_p2_fck);
+               clk_disable(omap->utmi_p2_fck);
+               clk_disable(omap->utmi_p1_fck);
        }
 
-       clk_disable(omap->utmi_p2_fck);
-       clk_disable(omap->utmi_p1_fck);
        clk_disable(omap->usbtll_ick);
        clk_disable(omap->usbtll_fck);
        clk_disable(omap->usbhost_fs_fck);
        clk_disable(omap->usbhost_hs_fck);
        clk_disable(omap->usbhost_ick);
 
+       /* The gpio_free migh sleep; so unlock the spinlock */
+       spin_unlock_irqrestore(&omap->lock, flags);
+
+       if (pdata->ehci_data->phy_reset) {
+               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
+                       gpio_free(pdata->ehci_data->reset_gpio_port[0]);
+
+               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
+                       gpio_free(pdata->ehci_data->reset_gpio_port[1]);
+       }
+       return;
+
 end_disble:
        spin_unlock_irqrestore(&omap->lock, flags);
 }