tegra: otg: enable OTG support
Suresh Mangipudi [Fri, 11 Feb 2011 08:43:44 +0000 (00:43 -0800)]
enabling OTG support for ventana on USB1.

Bug  724111

Original-Change-Id: I5ccc438a982030028ef6ffd466cd313506adf890
Reviewed-on: http://git-master/r/10492
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Tested-by: Bharat Nihalani <bnihalani@nvidia.com>

Rebase-Id: R70451addb28f8a93149675b6b0296e2f9a5edf98

arch/arm/mach-tegra/usb_phy.c
drivers/usb/gadget/fsl_udc_core.c
drivers/usb/host/ehci-tegra.c
drivers/usb/otg/tegra-otg.c

index cbd8d7a..5e0fa99 100644 (file)
@@ -31,6 +31,7 @@
 #include <mach/usb_phy.h>
 #include <mach/iomap.h>
 #include <mach/pinmux.h>
+#include "gpio-names.h"
 
 #define ULPI_VIEWPORT          0x170
 #define   ULPI_WAKEUP          (1 << 31)
@@ -368,6 +369,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
 {
        unsigned long val;
        void __iomem *base = phy->regs;
+       int gpio_status;
        struct tegra_utmip_config *config = phy->config;
 
        val = readl(base + USB_SUSP_CTRL);
@@ -484,6 +486,21 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
                val = readl(base + USB_SUSP_CTRL);
                val &= ~USB_SUSP_SET;
                writel(val, base + USB_SUSP_CTRL);
+               if (phy->mode == TEGRA_USB_PHY_MODE_HOST) {
+                       gpio_status = gpio_request(TEGRA_GPIO_PD0,"VBUS_BUS");
+                       if (gpio_status < 0) {
+                               printk("VBUS_USB1 request GPIO FAILED\n");
+                               WARN_ON(1);
+                       }
+                       tegra_gpio_enable(TEGRA_GPIO_PD0);
+                       gpio_status = gpio_direction_output(TEGRA_GPIO_PD0, 1);
+                       if (gpio_status < 0) {
+                               printk("VBUS_USB1 request GPIO DIRECTION FAILED \n");
+                               WARN_ON(1);
+                       }
+                       gpio_set_value(TEGRA_GPIO_PD0, 1);
+                       tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXK, TEGRA_TRI_NORMAL);
+               }
        }
 
        utmi_phy_clk_enable(phy);
@@ -504,6 +521,11 @@ static void utmi_phy_power_off(struct tegra_usb_phy *phy)
 
        utmi_phy_clk_disable(phy);
 
+       if (phy->instance == 0 && phy->mode == TEGRA_USB_PHY_MODE_HOST) {
+               gpio_free(TEGRA_GPIO_PD0);
+               tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXK, TEGRA_TRI_TRISTATE);
+       }
+
        if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
                val = readl(base + USB_SUSP_CTRL);
                val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0);
index 183aeb0..0e2d5bb 100644 (file)
@@ -1733,7 +1733,7 @@ static void setup_received_irq(struct fsl_udc *udc,
                udc->ep0_dir = (setup->bRequestType & USB_DIR_IN)
                                ?  USB_DIR_IN : USB_DIR_OUT;
                spin_unlock(&udc->lock);
-               if (udc->driver->setup(&udc->gadget,
+               if (udc->driver && udc->driver->setup(&udc->gadget,
                                &udc->local_setup_buff) < 0)
                        ep0stall(udc);
                spin_lock(&udc->lock);
@@ -1743,7 +1743,7 @@ static void setup_received_irq(struct fsl_udc *udc,
                /* No data phase, IN status from gadget */
                udc->ep0_dir = USB_DIR_IN;
                spin_unlock(&udc->lock);
-               if (udc->driver->setup(&udc->gadget,
+               if (udc->driver && udc->driver->setup(&udc->gadget,
                                &udc->local_setup_buff) < 0)
                        ep0stall(udc);
                spin_lock(&udc->lock);
@@ -2002,7 +2002,7 @@ static void suspend_irq(struct fsl_udc *udc)
        udc->usb_state = USB_STATE_SUSPENDED;
 
        /* report suspend to the driver, serial.c does not support this */
-       if (udc->driver->suspend)
+       if (udc->driver && udc->driver->suspend)
                udc->driver->suspend(&udc->gadget);
 }
 
@@ -2012,7 +2012,7 @@ static void bus_resume(struct fsl_udc *udc)
        udc->resume_state = 0;
 
        /* report resume to the driver, serial.c does not support this */
-       if (udc->driver->resume)
+       if (udc->driver && udc->driver->resume)
                udc->driver->resume(&udc->gadget);
 }
 
@@ -2026,7 +2026,8 @@ static int reset_queues(struct fsl_udc *udc)
 
        /* report disconnect; the driver is already quiesced */
        spin_unlock(&udc->lock);
-       udc->driver->disconnect(&udc->gadget);
+       if (udc->driver && udc->driver->disconnect)
+               udc->driver->disconnect(&udc->gadget);
        spin_lock(&udc->lock);
 
        return 0;
index 612f810..60249f5 100644 (file)
@@ -411,6 +411,9 @@ static void tegra_ehci_shutdown(struct usb_hcd *hcd)
                tegra_ehci_power_up(hcd);
 
        ehci_shutdown(hcd);
+
+       /* we are ready to shut down, powerdown the phy */
+       tegra_ehci_power_down(hcd);
 }
 
 static int tegra_ehci_setup(struct usb_hcd *hcd)
@@ -767,9 +770,12 @@ static int tegra_ehci_remove(struct platform_device *pdev)
        }
 #endif
 
+       /* Turn Off Interrupts */
+       ehci_writel(tegra->ehci, 0, &tegra->ehci->regs->intr_enable);
+       clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
        usb_remove_hcd(hcd);
        usb_put_hcd(hcd);
-
+       tegra_usb_phy_power_off(tegra->phy);
        tegra_usb_phy_close(tegra->phy);
        iounmap(hcd->regs);
 
index 5a75854..1a858b0 100644 (file)
@@ -43,6 +43,9 @@
 #define  USB_VBUS_STATUS       (1 << 10)
 #define  USB_INTS              (USB_VBUS_INT_STATUS | USB_ID_INT_STATUS)
 
+extern struct platform_device *tegra_usb_otg_host_register();
+extern void tegra_usb_otg_host_unregister(struct platform_device *pdev);
+
 struct tegra_otg_data {
        struct otg_transceiver otg;
        unsigned long int_status;
@@ -52,6 +55,7 @@ struct tegra_otg_data {
        int irq;
        struct platform_device *host;
        struct platform_device *pdev;
+       struct work_struct work;
 };
 
 static inline unsigned long otg_readl(struct tegra_otg_data *tegra,
@@ -79,58 +83,23 @@ static const char *tegra_state_name(enum usb_otg_state state)
 
 void tegra_start_host(struct tegra_otg_data *tegra)
 {
-       int retval;
-       struct platform_device *pdev;
-       struct platform_device *host = tegra->host;
-       void *platform_data;
-
-       pdev = platform_device_alloc(host->name, host->id);
-       if (!pdev)
-               return;
-
-       if (host->resource) {
-               retval = platform_device_add_resources(pdev, host->resource,
-                                                       host->num_resources);
-               if (retval)
-                       goto error;
+       if (!tegra->pdev) {
+               tegra->pdev = tegra_usb_otg_host_register();
        }
-
-       pdev->dev.dma_mask = host->dev.dma_mask;
-       pdev->dev.coherent_dma_mask = host->dev.coherent_dma_mask;
-
-       platform_data = kmalloc(sizeof(struct tegra_ehci_platform_data), GFP_KERNEL);
-       if (!platform_data)
-               goto error;
-
-       memcpy(platform_data, host->dev.platform_data,
-                               sizeof(struct tegra_ehci_platform_data));
-       pdev->dev.platform_data = platform_data;
-
-       retval = platform_device_add(pdev);
-       if (retval)
-               goto error_add;
-
-       tegra->pdev = pdev;
-       return;
-
-error_add:
-       kfree(platform_data);
-error:
-       pr_err("%s: failed to add the host contoller device\n", __func__);
-       platform_device_put(pdev);
 }
 
 void tegra_stop_host(struct tegra_otg_data *tegra)
 {
        if (tegra->pdev) {
-               platform_device_unregister(tegra->pdev);
+               tegra_usb_otg_host_unregister(tegra->pdev);
                tegra->pdev = NULL;
        }
 }
 
-static irqreturn_t tegra_otg_irq_thread(int irq, void *data)
+static void irq_work(struct work_struct *work)
 {
-       struct tegra_otg_data *tegra = data;
+       struct tegra_otg_data *tegra =
+               container_of(work, struct tegra_otg_data, work);
        struct otg_transceiver *otg = &tegra->otg;
        enum usb_otg_state from = otg->state;
        enum usb_otg_state to = OTG_STATE_UNDEFINED;
@@ -139,67 +108,72 @@ static irqreturn_t tegra_otg_irq_thread(int irq, void *data)
 
        clk_enable(tegra->clk);
 
-       status = otg_readl(tegra, USB_PHY_WAKEUP);
-
        spin_lock_irqsave(&tegra->lock, flags);
 
+       status = tegra->int_status;
+
        if (tegra->int_status & USB_ID_INT_STATUS) {
-               if (status & USB_ID_STATUS)
-                       to = OTG_STATE_A_SUSPEND;
+               if (status & USB_ID_STATUS) {
+                       if ((status & USB_VBUS_STATUS) && (from != OTG_STATE_A_HOST))
+                               to = OTG_STATE_B_PERIPHERAL;
+                       else
+                               to = OTG_STATE_A_SUSPEND;
+               }
                else
                        to = OTG_STATE_A_HOST;
-       } else if (tegra->int_status & USB_VBUS_INT_STATUS) {
-               if (status & USB_VBUS_STATUS)
-                       to = OTG_STATE_B_PERIPHERAL;
-               else
-                       to = OTG_STATE_A_SUSPEND;
        }
-
-       tegra->int_status = 0;
-
+       if (from != OTG_STATE_A_HOST) {
+               if (tegra->int_status & USB_VBUS_INT_STATUS) {
+                       if (status & USB_VBUS_STATUS)
+                               to = OTG_STATE_B_PERIPHERAL;
+                       else
+                               to = OTG_STATE_A_SUSPEND;
+               }
+       }
        spin_unlock_irqrestore(&tegra->lock, flags);
 
-       otg->state = to;
+       if (to != OTG_STATE_UNDEFINED) {
+               otg->state = to;
 
-       dev_info(tegra->otg.dev, "%s --> %s", tegra_state_name(from),
+               dev_info(tegra->otg.dev, "%s --> %s\n", tegra_state_name(from),
                                              tegra_state_name(to));
 
-       if (to == OTG_STATE_A_SUSPEND) {
-               if (from == OTG_STATE_A_HOST && tegra->host)
-                       tegra_stop_host(tegra);
-               else if (from == OTG_STATE_B_PERIPHERAL && otg->gadget)
-                       usb_gadget_vbus_disconnect(otg->gadget);
-       } else if (to == OTG_STATE_B_PERIPHERAL && otg->gadget) {
-               if (from == OTG_STATE_A_SUSPEND)
-                       usb_gadget_vbus_connect(otg->gadget);
-       } else if (to == OTG_STATE_A_HOST && tegra->host) {
-               if (from == OTG_STATE_A_SUSPEND)
+               if (to == OTG_STATE_A_SUSPEND) {
+                       if (from == OTG_STATE_A_HOST)
+                               tegra_stop_host(tegra);
+                       else if (from == OTG_STATE_B_PERIPHERAL && otg->gadget)
+                               usb_gadget_vbus_disconnect(otg->gadget);
+               } else if (to == OTG_STATE_B_PERIPHERAL && otg->gadget) {
+                       if (from == OTG_STATE_A_SUSPEND)
+                               usb_gadget_vbus_connect(otg->gadget);
+               } else if (to == OTG_STATE_A_HOST) {
+                       if (from == OTG_STATE_A_SUSPEND)
                        tegra_start_host(tegra);
+               }
        }
-
        clk_disable(tegra->clk);
 
-       return IRQ_HANDLED;
-
 }
 
 static irqreturn_t tegra_otg_irq(int irq, void *data)
 {
        struct tegra_otg_data *tegra = data;
+       unsigned long flags;
        unsigned long val;
 
-       spin_lock(&tegra->lock);
+       spin_lock_irqsave(&tegra->lock, flags);
+
        val = otg_readl(tegra, USB_PHY_WAKEUP);
        otg_writel(tegra, val, USB_PHY_WAKEUP);
 
-       /* and the interrupt enables into the interrupt status bits */
-       val = (val & (val << 1)) & USB_INTS;
-
-       tegra->int_status |= val;
+       if ((val & USB_ID_INT_STATUS) || (val & USB_VBUS_INT_STATUS)) {
+               tegra->int_status = val;
+               schedule_work(&tegra->work);
+       }
 
-       spin_unlock(&tegra->lock);
+       spin_unlock_irqrestore(&tegra->lock, flags);
 
-       return (val) ? IRQ_WAKE_THREAD : IRQ_NONE;
+       return IRQ_HANDLED;
 }
 
 static int tegra_otg_set_peripheral(struct otg_transceiver *otg,
@@ -213,16 +187,24 @@ static int tegra_otg_set_peripheral(struct otg_transceiver *otg,
 
        clk_enable(tegra->clk);
        val = otg_readl(tegra, USB_PHY_WAKEUP);
-       val &= ~(USB_VBUS_INT_STATUS | USB_ID_INT_STATUS);
-
-       if (gadget)
-               val |= (USB_VBUS_INT_EN | USB_VBUS_WAKEUP_EN);
-       else
-               val &= ~(USB_VBUS_INT_EN | USB_VBUS_WAKEUP_EN);
-
+       val |= (USB_VBUS_INT_EN | USB_VBUS_WAKEUP_EN);
+       val |= (USB_ID_INT_EN | USB_ID_PIN_WAKEUP_EN);
        otg_writel(tegra, val, USB_PHY_WAKEUP);
        clk_disable(tegra->clk);
 
+       if ((val & USB_ID_STATUS) && (val & USB_VBUS_STATUS)) {
+               val |= USB_VBUS_INT_STATUS;
+       } else if (!(val & USB_ID_STATUS)) {
+               val |= USB_ID_INT_STATUS;
+       } else {
+               val &= ~(USB_ID_INT_STATUS | USB_VBUS_INT_STATUS);
+       }
+
+       if ((val & USB_ID_INT_STATUS) || (val & USB_VBUS_INT_STATUS)) {
+               tegra->int_status = val;
+               schedule_work (&tegra->work);
+       }
+
        return 0;
 }
 
@@ -239,10 +221,7 @@ static int tegra_otg_set_host(struct otg_transceiver *otg,
        val = otg_readl(tegra, USB_PHY_WAKEUP);
        val &= ~(USB_VBUS_INT_STATUS | USB_ID_INT_STATUS);
 
-       if (host)
-               val |= USB_ID_INT_EN | USB_ID_PIN_WAKEUP_EN;
-       else
-               val &= ~(USB_ID_INT_EN | USB_ID_PIN_WAKEUP_EN);
+       val |= (USB_ID_INT_EN | USB_ID_PIN_WAKEUP_EN);
        otg_writel(tegra, val, USB_PHY_WAKEUP);
        clk_disable(tegra->clk);
 
@@ -263,7 +242,6 @@ static int tegra_otg_probe(struct platform_device *pdev)
 {
        struct tegra_otg_data *tegra;
        struct resource *res;
-       unsigned long val;
        int err;
 
        tegra = kzalloc(sizeof(struct tegra_otg_data), GFP_KERNEL);
@@ -305,14 +283,6 @@ static int tegra_otg_probe(struct platform_device *pdev)
                goto err_io;
        }
 
-       val = otg_readl(tegra, USB_PHY_WAKEUP);
-
-       val &= ~(USB_VBUS_INT_STATUS | USB_VBUS_INT_EN |
-                USB_ID_INT_STATUS | USB_ID_INT_EN |
-                USB_VBUS_WAKEUP_EN | USB_ID_PIN_WAKEUP_EN);
-
-       otg_writel(tegra, val, USB_PHY_WAKEUP);
-
        tegra->otg.state = OTG_STATE_A_SUSPEND;
 
        err = otg_set_transceiver(&tegra->otg);
@@ -329,12 +299,13 @@ static int tegra_otg_probe(struct platform_device *pdev)
        }
        tegra->irq = res->start;
        err = request_threaded_irq(tegra->irq, tegra_otg_irq,
-                                  tegra_otg_irq_thread,
+                                  NULL,
                                   IRQF_SHARED, "tegra-otg", tegra);
        if (err) {
                dev_err(&pdev->dev, "Failed to register IRQ\n");
                goto err_irq;
        }
+       INIT_WORK (&tegra->work, irq_work);
 
        dev_info(&pdev->dev, "otg transceiver registered\n");
        return 0;