|
@@ -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;
|