diff options
Diffstat (limited to 'drivers/usb/gadget/pxa2xx_udc.c')
-rw-r--r-- | drivers/usb/gadget/pxa2xx_udc.c | 70 |
1 files changed, 68 insertions, 2 deletions
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index fff027d30a09..f1adcf8b2023 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -150,6 +150,39 @@ MODULE_PARM_DESC (fifo_mode, "pxa2xx udc fifo mode"); static void pxa2xx_ep_fifo_flush (struct usb_ep *ep); static void nuke (struct pxa2xx_ep *, int status); +/* one GPIO should be used to detect VBUS from the host */ +static int is_vbus_present(void) +{ + struct pxa2xx_udc_mach_info *mach = the_controller->mach; + + if (mach->gpio_vbus) + return pxa_gpio_get(mach->gpio_vbus); + if (mach->udc_is_connected) + return mach->udc_is_connected(); + return 1; +} + +/* one GPIO should control a D+ pullup, so host sees this device (or not) */ +static void pullup_off(void) +{ + struct pxa2xx_udc_mach_info *mach = the_controller->mach; + + if (mach->gpio_pullup) + pxa_gpio_set(mach->gpio_pullup, 0); + else if (mach->udc_command) + mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); +} + +static void pullup_on(void) +{ + struct pxa2xx_udc_mach_info *mach = the_controller->mach; + + if (mach->gpio_pullup) + pxa_gpio_set(mach->gpio_pullup, 1); + else if (mach->udc_command) + mach->udc_command(PXA2XX_UDC_CMD_CONNECT); +} + static void pio_irq_enable(int bEndpointAddress) { bEndpointAddress &= 0xf; @@ -1721,6 +1754,16 @@ lubbock_vbus_irq(int irq, void *_dev, struct pt_regs *r) #endif +static irqreturn_t +udc_vbus_irq(int irq, void *_dev, struct pt_regs *r) +{ + struct pxa2xx_udc *dev = _dev; + int vbus = pxa_gpio_get(dev->mach->gpio_vbus); + + pxa2xx_udc_vbus_session(&dev->gadget, vbus); + return IRQ_HANDLED; +} + /*-------------------------------------------------------------------------*/ @@ -2438,7 +2481,7 @@ static struct pxa2xx_udc memory = { static int __init pxa2xx_udc_probe(struct platform_device *pdev) { struct pxa2xx_udc *dev = &memory; - int retval, out_dma = 1; + int retval, out_dma = 1, vbus_irq; u32 chiprev; /* insist on Intel/ARM/XScale */ @@ -2502,6 +2545,16 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) /* other non-static parts of init */ dev->dev = &pdev->dev; dev->mach = pdev->dev.platform_data; + if (dev->mach->gpio_vbus) { + vbus_irq = IRQ_GPIO(dev->mach->gpio_vbus & GPIO_MD_MASK_NR); + pxa_gpio_mode((dev->mach->gpio_vbus & GPIO_MD_MASK_NR) + | GPIO_IN); + set_irq_type(vbus_irq, IRQT_BOTHEDGE); + } else + vbus_irq = 0; + if (dev->mach->gpio_pullup) + pxa_gpio_mode((dev->mach->gpio_pullup & GPIO_MD_MASK_NR) + | GPIO_OUT | GPIO_DFLT_LOW); init_timer(&dev->timer); dev->timer.function = udc_watchdog; @@ -2557,8 +2610,19 @@ lubbock_fail0: HEX_DISPLAY(dev->stats.irqs); LUB_DISC_BLNK_LED &= 0xff; #endif - } + } else #endif + if (vbus_irq) { + retval = request_irq(vbus_irq, udc_vbus_irq, + SA_INTERRUPT | SA_SAMPLE_RANDOM, + driver_name, dev); + if (retval != 0) { + printk(KERN_ERR "%s: can't get irq %i, err %d\n", + driver_name, vbus_irq, retval); + free_irq(IRQ_USB, dev); + return -EBUSY; + } + } create_proc_files(); return 0; @@ -2587,6 +2651,8 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev) free_irq(LUBBOCK_USB_IRQ, dev); } #endif + if (dev->mach->gpio_vbus) + free_irq(IRQ_GPIO(dev->mach->gpio_vbus), dev); platform_set_drvdata(pdev, NULL); the_controller = NULL; return 0; |