diff options
Diffstat (limited to 'drivers/usb/gadget/pxa2xx_udc.c')
-rw-r--r-- | drivers/usb/gadget/pxa2xx_udc.c | 79 |
1 files changed, 72 insertions, 7 deletions
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 269ce7f4ad66..f1adcf8b2023 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -27,7 +27,6 @@ #undef DEBUG // #define VERBOSE DBG_VERBOSE -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/ioport.h> @@ -60,7 +59,7 @@ #include <linux/usb_ch9.h> #include <linux/usb_gadget.h> -#include <asm/arch/hardware/intel_udc.h> +#include <asm/arch/udc.h> /* @@ -151,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; @@ -1722,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; +} + /*-------------------------------------------------------------------------*/ @@ -2439,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 */ @@ -2503,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; @@ -2522,7 +2574,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) /* irq setup after old hardware state is cleaned up */ retval = request_irq(IRQ_USB, pxa2xx_udc_irq, - SA_INTERRUPT, driver_name, dev); + IRQF_DISABLED, driver_name, dev); if (retval != 0) { printk(KERN_ERR "%s: can't get irq %i, err %d\n", driver_name, IRQ_USB, retval); @@ -2534,7 +2586,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) if (machine_is_lubbock()) { retval = request_irq(LUBBOCK_USB_DISC_IRQ, lubbock_vbus_irq, - SA_INTERRUPT | SA_SAMPLE_RANDOM, + IRQF_DISABLED | IRQF_SAMPLE_RANDOM, driver_name, dev); if (retval != 0) { printk(KERN_ERR "%s: can't get irq %i, err %d\n", @@ -2545,7 +2597,7 @@ lubbock_fail0: } retval = request_irq(LUBBOCK_USB_IRQ, lubbock_vbus_irq, - SA_INTERRUPT | SA_SAMPLE_RANDOM, + IRQF_DISABLED | IRQF_SAMPLE_RANDOM, driver_name, dev); if (retval != 0) { printk(KERN_ERR "%s: can't get irq %i, err %d\n", @@ -2558,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; @@ -2588,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; |