summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/pxa2xx_udc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/pxa2xx_udc.c')
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c81
1 files changed, 74 insertions, 7 deletions
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index fff027d..1ed506e 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -43,11 +43,11 @@
#include <linux/mm.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/irq.h>
#include <asm/byteorder.h>
#include <asm/dma.h>
#include <asm/io.h>
-#include <asm/irq.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <asm/unaligned.h>
@@ -110,7 +110,7 @@ static int use_dma = 1;
module_param(use_dma, bool, 0);
MODULE_PARM_DESC (use_dma, "true to use dma");
-static void dma_nodesc_handler (int dmach, void *_ep, struct pt_regs *r);
+static void dma_nodesc_handler (int dmach, void *_ep);
static void kick_dma(struct pxa2xx_ep *ep, struct pxa2xx_request *req);
#ifdef USE_OUT_DMA
@@ -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;
@@ -795,7 +828,7 @@ static void cancel_dma(struct pxa2xx_ep *ep)
}
/* dma channel stopped ... normal tx end (IN), or on error (IN/OUT) */
-static void dma_nodesc_handler(int dmach, void *_ep, struct pt_regs *r)
+static void dma_nodesc_handler(int dmach, void *_ep)
{
struct pxa2xx_ep *ep = _ep;
struct pxa2xx_request *req;
@@ -1691,7 +1724,7 @@ EXPORT_SYMBOL(usb_gadget_unregister_driver);
*/
static irqreturn_t
-lubbock_vbus_irq(int irq, void *_dev, struct pt_regs *r)
+lubbock_vbus_irq(int irq, void *_dev)
{
struct pxa2xx_udc *dev = _dev;
int vbus;
@@ -1721,6 +1754,15 @@ lubbock_vbus_irq(int irq, void *_dev, struct pt_regs *r)
#endif
+static irqreturn_t udc_vbus_irq(int irq, void *_dev)
+{
+ struct pxa2xx_udc *dev = _dev;
+ int vbus = pxa_gpio_get(dev->mach->gpio_vbus);
+
+ pxa2xx_udc_vbus_session(&dev->gadget, vbus);
+ return IRQ_HANDLED;
+}
+
/*-------------------------------------------------------------------------*/
@@ -2041,7 +2083,7 @@ static void handle_ep(struct pxa2xx_ep *ep)
* could cause usb protocol errors.
*/
static irqreturn_t
-pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r)
+pxa2xx_udc_irq(int irq, void *_dev)
{
struct pxa2xx_udc *dev = _dev;
int handled;
@@ -2430,6 +2472,7 @@ static struct pxa2xx_udc memory = {
#define PXA210_B1 0x00000123
#define PXA210_B0 0x00000122
#define IXP425_A0 0x000001c1
+#define IXP425_B0 0x000001f1
#define IXP465_AD 0x00000200
/*
@@ -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 */
@@ -2467,6 +2510,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
break;
#elif defined(CONFIG_ARCH_IXP4XX)
case IXP425_A0:
+ case IXP425_B0:
case IXP465_AD:
dev->has_cfr = 1;
out_dma = 0;
@@ -2502,6 +2546,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 +2611,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 +2652,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;