usb: gadget: mv_udc: add otg relative code
authorNeil Zhang <zhangwm@marvell.com>
Wed, 30 Nov 2011 01:57:13 +0000 (09:57 +0800)
committerFelipe Balbi <balbi@ti.com>
Mon, 12 Dec 2011 09:45:22 +0000 (11:45 +0200)
Add otg relative code, make it possible to switch between host and
device.

Signed-off-by: Neil Zhang <zhangwm@marvell.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/gadget/mv_udc.h
drivers/usb/gadget/mv_udc_core.c

index daa75c1..b2c36ee 100644 (file)
@@ -216,6 +216,8 @@ struct mv_udc {
        struct work_struct      vbus_work;
        struct workqueue_struct *qwork;
 
+       struct otg_transceiver  *transceiver;
+
        struct mv_usb_platform_data     *pdata;
 
        /* some SOC has mutiple clock sources for USB*/
index 9376a74..647cc3a 100644 (file)
@@ -1407,6 +1407,20 @@ static int mv_udc_start(struct usb_gadget_driver *driver,
                return retval;
        }
 
+       if (udc->transceiver) {
+               retval = otg_set_peripheral(udc->transceiver, &udc->gadget);
+               if (retval) {
+                       dev_err(&udc->dev->dev,
+                               "unable to register peripheral to otg\n");
+                       if (driver->unbind) {
+                               driver->unbind(&udc->gadget);
+                               udc->gadget.dev.driver = NULL;
+                               udc->driver = NULL;
+                       }
+                       return retval;
+               }
+       }
+
        /* pullup is always on */
        mv_udc_pullup(&udc->gadget, 1);
 
@@ -2109,7 +2123,12 @@ static int __devexit mv_udc_remove(struct platform_device *dev)
                destroy_workqueue(udc->qwork);
        }
 
-       if (udc->pdata && udc->pdata->vbus && udc->clock_gating)
+       /*
+        * If we have transceiver inited,
+        * then vbus irq will not be requested in udc driver.
+        */
+       if (udc->pdata && udc->pdata->vbus
+               && udc->clock_gating && udc->transceiver == NULL)
                free_irq(udc->pdata->vbus->irq, &dev->dev);
 
        /* free memory allocated in probe */
@@ -2182,6 +2201,11 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
 
        udc->dev = dev;
 
+#ifdef CONFIG_USB_OTG_UTILS
+       if (pdata->mode == MV_USB_MODE_OTG)
+               udc->transceiver = otg_get_transceiver();
+#endif
+
        udc->clknum = pdata->clknum;
        for (clk_i = 0; clk_i < udc->clknum; clk_i++) {
                udc->clk[clk_i] = clk_get(&dev->dev, pdata->clkname[clk_i]);
@@ -2328,7 +2352,9 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
        eps_init(udc);
 
        /* VBUS detect: we can disable/enable clock on demand.*/
-       if (pdata->vbus) {
+       if (udc->transceiver)
+               udc->clock_gating = 1;
+       else if (pdata->vbus) {
                udc->clock_gating = 1;
                retval = request_threaded_irq(pdata->vbus->irq, NULL,
                                mv_udc_vbus_irq, IRQF_ONESHOT, "vbus", udc);
@@ -2371,7 +2397,8 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
        return 0;
 
 err_unregister:
-       if (udc->pdata && udc->pdata->vbus && udc->clock_gating)
+       if (udc->pdata && udc->pdata->vbus
+               && udc->clock_gating && udc->transceiver == NULL)
                free_irq(pdata->vbus->irq, &dev->dev);
        device_unregister(&udc->gadget.dev);
 err_free_irq: