#include <linux/proc_fs.h>
 #include <linux/clk.h>
 #include <linux/irq.h>
+#include <linux/gpio.h>
 
 #include <asm/byteorder.h>
 #include <mach/hardware.h>
        .fifo_flush     = pxa_ep_fifo_flush,
 };
 
+/**
+ * dplus_pullup - Connect or disconnect pullup resistor to D+ pin
+ * @udc: udc device
+ * @on: 0 if disconnect pullup resistor, 1 otherwise
+ * Context: any
+ *
+ * Handle D+ pullup resistor, make the device visible to the usb bus, and
+ * declare it as a full speed usb device
+ */
+static void dplus_pullup(struct pxa_udc *udc, int on)
+{
+       if (on) {
+               if (gpio_is_valid(udc->mach->gpio_pullup))
+                       gpio_set_value(udc->mach->gpio_pullup,
+                                      !udc->mach->gpio_pullup_inverted);
+               if (udc->mach->udc_command)
+                       udc->mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
+       } else {
+               if (gpio_is_valid(udc->mach->gpio_pullup))
+                       gpio_set_value(udc->mach->gpio_pullup,
+                                      udc->mach->gpio_pullup_inverted);
+               if (udc->mach->udc_command)
+                       udc->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
+       }
+       udc->pullup_on = on;
+}
 
 /**
  * pxa_udc_get_frame - Returns usb frame number
        return 0;
 }
 
+static void udc_enable(struct pxa_udc *udc);
+static void udc_disable(struct pxa_udc *udc);
+
+/**
+ * should_enable_udc - Tells if UDC should be enabled
+ * @udc: udc device
+ * Context: any
+ *
+ * The UDC should be enabled if :
+ *  - the pullup resistor is connected
+ *  - and a gadget driver is bound
+ *
+ * Returns 1 if UDC should be enabled, 0 otherwise
+ */
+static int should_enable_udc(struct pxa_udc *udc)
+{
+       int put_on;
+
+       put_on = ((udc->pullup_on) && (udc->driver));
+       return put_on;
+}
+
+/**
+ * should_disable_udc - Tells if UDC should be disabled
+ * @udc: udc device
+ * Context: any
+ *
+ * The UDC should be disabled if :
+ *  - the pullup resistor is not connected
+ *  - or no gadget driver is bound
+ *
+ * Returns 1 if UDC should be disabled
+ */
+static int should_disable_udc(struct pxa_udc *udc)
+{
+       int put_off;
+
+       put_off = ((!udc->pullup_on) || (!udc->driver));
+       return put_off;
+}
+
+/**
+ * pxa_udc_pullup - Offer manual D+ pullup control
+ * @_gadget: usb gadget using the control
+ * @is_active: 0 if disconnect, else connect D+ pullup resistor
+ * Context: !in_interrupt()
+ *
+ * Returns 0 if OK, -EOPNOTSUPP if udc driver doesn't handle D+ pullup
+ */
+static int pxa_udc_pullup(struct usb_gadget *_gadget, int is_active)
+{
+       struct pxa_udc *udc = to_gadget_udc(_gadget);
+
+       if (!gpio_is_valid(udc->mach->gpio_pullup) && !udc->mach->udc_command)
+               return -EOPNOTSUPP;
+
+       dplus_pullup(udc, is_active);
+
+       if (should_enable_udc(udc))
+               udc_enable(udc);
+       if (should_disable_udc(udc))
+               udc_disable(udc);
+       return 0;
+}
+
 static const struct usb_gadget_ops pxa_udc_ops = {
        .get_frame      = pxa_udc_get_frame,
        .wakeup         = pxa_udc_wakeup,
+       .pullup         = pxa_udc_pullup,
        /* current versions must always be self-powered */
 };
 
 /**
  * udc_disable - disable udc device controller
  * @udc: udc device
+ * Context: any
  *
  * Disables the udc device : disables clocks, udc interrupts, control endpoint
  * interrupts.
  */
 static void udc_disable(struct pxa_udc *udc)
 {
+       if (!udc->enabled)
+               return;
+
        udc_writel(udc, UDCICR0, 0);
        udc_writel(udc, UDCICR1, 0);
 
 
        ep0_idle(udc);
        udc->gadget.speed = USB_SPEED_UNKNOWN;
-       if (udc->mach->udc_command)
-               udc->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
+
+       udc->enabled = 0;
 }
 
 /**
  */
 static void udc_enable(struct pxa_udc *udc)
 {
+       if (udc->enabled)
+               return;
+
        udc_writel(udc, UDCICR0, 0);
        udc_writel(udc, UDCICR1, 0);
        udc_clear_mask_UDCCR(udc, UDCCR_UDE);
        /* enable ep0 irqs */
        pio_irq_enable(&udc->pxa_ep[0]);
 
-       dev_info(udc->dev, "UDC connecting\n");
-       if (udc->mach->udc_command)
-               udc->mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
+       udc->enabled = 1;
 }
 
 /**
  * usb traffic follows until a disconnect is reported.  Then a host may connect
  * again, or the driver might get unbound.
  *
+ * Note that the udc is not automatically enabled. Check function
+ * should_enable_udc().
+ *
  * Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise
  */
 int usb_gadget_register_driver(struct usb_gadget_driver *driver)
        /* first hook up the driver ... */
        udc->driver = driver;
        udc->gadget.dev.driver = &driver->driver;
+       dplus_pullup(udc, 1);
 
        retval = device_add(&udc->gadget.dev);
        if (retval) {
        dev_dbg(udc->dev, "registered gadget driver '%s'\n",
                driver->driver.name);
 
-       udc_enable(udc);
+       if (should_enable_udc(udc))
+               udc_enable(udc);
        return 0;
 
 bind_fail:
 
        stop_activity(udc, driver);
        udc_disable(udc);
+       dplus_pullup(udc, 0);
 
        driver->unbind(&udc->gadget);
        udc->driver = NULL;
 {
        struct resource *regs;
        struct pxa_udc *udc = &memory;
-       int retval;
+       int retval = 0, gpio;
 
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!regs)
        udc->dev = &pdev->dev;
        udc->mach = pdev->dev.platform_data;
 
+       gpio = udc->mach->gpio_pullup;
+       if (gpio_is_valid(gpio)) {
+               retval = gpio_request(gpio, "USB D+ pullup");
+               if (retval == 0)
+                       gpio_direction_output(gpio,
+                                      udc->mach->gpio_pullup_inverted);
+       }
+       if (retval) {
+               dev_err(&pdev->dev, "Couldn't request gpio %d : %d\n",
+                       gpio, retval);
+               return retval;
+       }
+
        udc->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(udc->clk)) {
                retval = PTR_ERR(udc->clk);
 static int __exit pxa_udc_remove(struct platform_device *_dev)
 {
        struct pxa_udc *udc = platform_get_drvdata(_dev);
+       int gpio = udc->mach->gpio_pullup;
 
        usb_gadget_unregister_driver(udc->driver);
        free_irq(udc->irq, udc);
        pxa_cleanup_debugfs(udc);
+       if (gpio_is_valid(gpio))
+               gpio_free(gpio);
 
        platform_set_drvdata(_dev, NULL);
        the_controller = NULL;
        }
 
        udc_disable(udc);
+       udc->pullup_resume = udc->pullup_on;
+       dplus_pullup(udc, 0);
 
        return 0;
 }
                                ep->udccsr_value, ep->udccr_value);
        }
 
-       udc_enable(udc);
+       dplus_pullup(udc, udc->pullup_resume);
+       if (should_enable_udc(udc))
+               udc_enable(udc);
        /*
         * We do not handle OTG yet.
         *