usb: otg: Remove the force_irq hack
authorBenoit Goby <benoit@android.com>
Wed, 1 Sep 2010 00:22:26 +0000 (17:22 -0700)
committerColin Cross <ccross@android.com>
Wed, 6 Oct 2010 23:51:01 +0000 (16:51 -0700)
Dynamically add/remove the ehci platform device and use
vbus_connect/vbus_disconnect to notify the gadget driver of
OTG state changes.
Only enable the clock when needed, as we rarely need to access
the registers.

Change-Id: Id198822c58f50252361333c3a99c416a3baaace2
Signed-off-by: Benoit Goby <benoit@android.com>
drivers/usb/otg/cpcap-otg.c

index b19681a05352791c523a62ca8800e8916e2aba0c..cfb7c3ef0cc17dfbae0cb337133c76e01f519405 100644 (file)
@@ -25,8 +25,6 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/err.h>
-#include <mach/usb_phy.h>
-#include <mach/legacy_irq.h>
 
 #define TEGRA_USB_PHY_WAKEUP_REG_OFFSET                0x408
 #define   TEGRA_VBUS_WAKEUP_SW_VALUE           (1 << 12)
@@ -39,7 +37,8 @@ struct cpcap_otg_data {
        struct notifier_block nb;
        void __iomem *regs;
        struct clk *clk;
-       int irq;
+       struct platform_device *host;
+       struct platform_device *pdev;
 };
 
 static const char *cpcap_state_name(enum usb_otg_state state)
@@ -53,13 +52,41 @@ static const char *cpcap_state_name(enum usb_otg_state state)
        return "INVALID";
 }
 
-static irqreturn_t cpcap_otg_irq(int irq, void *data)
+void cpcap_start_host(struct cpcap_otg_data *cpcap)
 {
-       if (tegra_legacy_force_irq_status(irq)) {
-               tegra_legacy_force_irq_clr(irq);
-               return IRQ_HANDLED;
+       int retval;
+
+       cpcap->pdev = platform_device_alloc(cpcap->host->name, cpcap->host->id);
+       if (!cpcap->pdev)
+               return;
+
+       if (cpcap->host->resource) {
+               retval = platform_device_add_resources(cpcap->pdev,
+                                               cpcap->host->resource,
+                                               cpcap->host->num_resources);
+               if (retval)
+                       goto error;
+       }
+
+       cpcap->pdev->dev.dma_mask = cpcap->host->dev.dma_mask;
+       cpcap->pdev->dev.coherent_dma_mask = cpcap->host->dev.coherent_dma_mask;
+
+       retval = platform_device_add(cpcap->pdev);
+       if (retval)
+               goto error;
+
+       return;
+error:
+       pr_err("%s: failed to add the host contoller device\n", __func__);
+       platform_device_put(cpcap->pdev);
+}
+
+void cpcap_stop_host(struct cpcap_otg_data *cpcap)
+{
+       if (cpcap->pdev) {
+               platform_device_unregister(cpcap->pdev);
+               cpcap->pdev = NULL;
        }
-       return IRQ_NONE;
 }
 
 static int cpcap_otg_notify(struct notifier_block *nb, unsigned long event,
@@ -90,34 +117,35 @@ static int cpcap_otg_notify(struct notifier_block *nb, unsigned long event,
        dev_info(cpcap->otg.dev, "%s --> %s", cpcap_state_name(from),
                                              cpcap_state_name(to));
 
+       clk_enable(cpcap->clk);
+
        if ((to == OTG_STATE_A_HOST) && (from == OTG_STATE_A_SUSPEND)
-                       && otg->host) {
+                       && cpcap->host) {
                hcd = (struct usb_hcd *)otg->host;
 
-               set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-               clk_enable(cpcap->clk);
-
                val = readl(cpcap->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET);
                val &= ~TEGRA_ID_SW_VALUE;
                writel(val, cpcap->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET);
 
+               cpcap_start_host(cpcap);
+
        } else if ((to == OTG_STATE_A_SUSPEND) && (from == OTG_STATE_A_HOST)
-                       && otg->host) {
+                       && cpcap->host) {
                val = readl(cpcap->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET);
                val |= TEGRA_ID_SW_VALUE;
                writel(val, cpcap->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET);
 
-               clk_disable(cpcap->clk);
+               cpcap_stop_host(cpcap);
 
        } else if ((to == OTG_STATE_B_PERIPHERAL)
                        && (from == OTG_STATE_A_SUSPEND)
                        && otg->gadget) {
-               clk_enable(cpcap->clk);
-
                val = readl(cpcap->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET);
                val |= TEGRA_VBUS_WAKEUP_SW_VALUE;
                writel(val, cpcap->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET);
 
+               usb_gadget_vbus_connect(otg->gadget);
+
        } else if ((to == OTG_STATE_A_SUSPEND)
                        && (from == OTG_STATE_B_PERIPHERAL)
                        && otg->gadget) {
@@ -125,11 +153,11 @@ static int cpcap_otg_notify(struct notifier_block *nb, unsigned long event,
                val &= ~TEGRA_VBUS_WAKEUP_SW_VALUE;
                writel(val, cpcap->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET);
 
-               clk_disable(cpcap->clk);
-       } else
-               return 0;
+               usb_gadget_vbus_disconnect(otg->gadget);
+       }
+
+       clk_disable(cpcap->clk);
 
-       tegra_legacy_force_irq_set(cpcap->irq);
        return 0;
 }
 
@@ -175,6 +203,7 @@ static int cpcap_otg_probe(struct platform_device *pdev)
        cpcap->otg.set_peripheral = cpcap_otg_set_peripheral;
        cpcap->otg.set_suspend = cpcap_otg_set_suspend;
        cpcap->otg.set_power = cpcap_otg_set_power;
+       cpcap->host = pdev->dev.platform_data;
 
        platform_set_drvdata(pdev, cpcap);
 
@@ -201,21 +230,6 @@ static int cpcap_otg_probe(struct platform_device *pdev)
                goto err_io;
        }
 
-       cpcap->irq = platform_get_irq(pdev, 0);
-       if (cpcap->irq < 0) {
-               dev_err(&pdev->dev, "Failed to get IRQ\n");
-               err = -ENXIO;
-               goto err_irq;
-       }
-
-       err = request_irq(cpcap->irq, cpcap_otg_irq, IRQF_SHARED,
-                       "cpcap-otg", cpcap);
-       if (err) {
-               dev_err(&pdev->dev, "cannot request irq %d err %d\n",
-                               cpcap->irq, err);
-               goto err_irq;
-       }
-
        val = readl(cpcap->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET);
        val |= TEGRA_VBUS_WAKEUP_SW_ENABLE | TEGRA_ID_SW_ENABLE;
        val |= TEGRA_ID_SW_VALUE;
@@ -238,8 +252,6 @@ static int cpcap_otg_probe(struct platform_device *pdev)
        return 0;
 
 err_otg:
-       free_irq(cpcap->irq, cpcap);
-err_irq:
        iounmap(cpcap->regs);
 err_io:
        clk_disable(cpcap->clk);
@@ -256,7 +268,6 @@ static int __exit cpcap_otg_remove(struct platform_device *pdev)
        struct cpcap_otg_data *cpcap = platform_get_drvdata(pdev);
 
        otg_set_transceiver(NULL);
-       free_irq(cpcap->irq, cpcap);
        iounmap(cpcap->regs);
        clk_disable(cpcap->clk);
        clk_put(cpcap->clk);