Commit bf1ca153 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] USB Gadget: pxa2xx_udc updates

[USB] pxa2xx_udc updates, mostly for non-Lubbock hardware

  - IXP 42x UDC support (Greg Weeks)

  - remove Lubbock-specific build assumption (Guennadi Liakhovetski)

  - handle D+ pullup right on iPaqs, e7xx, etc (HH.org)

  - don't unbind() with irqs blocked; matches other controller drivers,
    and network layer expectations

  - handle some deferred ep0 responses better

  - support iso transfers (needs fifo size tracking)
parent eb9c3a28
/*
* linux/drivers/usb/gadget/pxa2xx_udc.c
* Intel PXA2xx on-chip full speed USB device controllers
* Intel PXA2xx and IXP4xx on-chip full speed USB device controllers
*
* Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker)
* Copyright (C) 2003 Robert Schwebel, Pengutronix
......@@ -59,12 +59,11 @@
#include <asm/arch/udc.h>
#include "pxa2xx_udc.h"
/*
* This driver handles the USB Device Controller (UDC) in Intel's PXA 2xx
* series processors. The UDC for the IXP 4xx series is very similar.
* There are fifteen endpoints, in addition to ep0.
*
* Such controller drivers work with a gadget driver. The gadget driver
* returns descriptors, implements configuration and data protocols used
......@@ -78,7 +77,7 @@
* pxa250 a0/a1 b0/b1/b2 sure act like they're still there.
*/
#define DRIVER_VERSION "7-Nov-2003"
#define DRIVER_VERSION "14-Dec-2003"
#define DRIVER_DESC "PXA 2xx USB Device Controller driver"
......@@ -95,6 +94,19 @@ static const char ep0name [] = "ep0";
#define UDC_PROC_FILE
#endif
#ifdef CONFIG_ARCH_IXP425
#undef USE_DMA
/* cpu-specific register addresses are compiled in to this code */
#ifdef CONFIG_ARCH_PXA
#error "Can't configure both IXP and PXA"
#endif
#endif
#include "pxa2xx_udc.h"
#ifdef CONFIG_EMBEDDED
/* few strings, and little code to use them */
#undef DEBUG
......@@ -215,7 +227,8 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
if (!_ep || !desc || ep->desc || _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT
|| ep->bEndpointAddress != desc->bEndpointAddress
|| ep->ep.maxpacket < desc->wMaxPacketSize) {
|| ep->fifo_size < le16_to_cpu
(desc->wMaxPacketSize)) {
DMSG("%s, bad ep or descriptor\n", __FUNCTION__);
return -EINVAL;
}
......@@ -230,7 +243,8 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
/* hardware _could_ do smaller, but driver doesn't */
if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
&& desc->wMaxPacketSize != BULK_FIFO_SIZE)
&& le16_to_cpu (desc->wMaxPacketSize)
!= BULK_FIFO_SIZE)
|| !desc->wMaxPacketSize) {
DMSG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name);
return -ERANGE;
......@@ -246,6 +260,7 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
ep->dma = -1;
ep->stopped = 0;
ep->pio_irqs = ep->dma_irqs = 0;
ep->ep.maxpacket = le16_to_cpu (desc->wMaxPacketSize);
/* flush fifo (mostly for OUT buffers) */
pxa2xx_ep_fifo_flush (_ep);
......@@ -258,14 +273,14 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
*/
switch (ep->bmAttributes) {
case USB_ENDPOINT_XFER_ISOC:
if (desc->wMaxPacketSize % 32)
if (le16_to_cpu(desc->wMaxPacketSize) % 32)
break;
// fall through
case USB_ENDPOINT_XFER_BULK:
if (!use_dma || !ep->reg_drcmr)
break;
ep->dma = pxa_request_dma ((char *)_ep->name,
(desc->wMaxPacketSize > 64)
(le16_to_cpu (desc->wMaxPacketSize) > 64)
? DMA_PRIO_MEDIUM /* some iso */
: DMA_PRIO_LOW,
dma_nodesc_handler, ep);
......@@ -437,7 +452,7 @@ write_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req)
{
unsigned max;
max = ep->desc->wMaxPacketSize;
max = le16_to_cpu(ep->desc->wMaxPacketSize);
do {
unsigned count;
int is_last, is_short;
......@@ -454,13 +469,7 @@ write_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req)
else
is_last = 1;
/* interrupt/iso maxpacket may not fill the fifo */
is_short = unlikely (max < ep->ep.maxpacket);
/* FIXME ep.maxpacket should be the current size,
* modified (for periodic endpoints) when the
* ep is enabled. do that, re-init as needed,
* and change maxpacket refs accordingly.
*/
is_short = unlikely (max < ep->fifo_size);
}
DBG(DBG_VERY_NOISY, "wrote %s %d bytes%s%s %d left %p\n",
......@@ -598,7 +607,7 @@ read_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req)
req->req.actual += min (count, bufferspace);
} else /* zlp */
count = 0;
is_short = (count < ep->desc->wMaxPacketSize);
is_short = (count < ep->ep.maxpacket);
DBG(DBG_VERY_NOISY, "read %s %02x, %d bytes%s req %p %d/%d\n",
ep->ep.name, udccs, count,
is_short ? "/S" : "",
......@@ -897,13 +906,14 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
* we can report per-packet status. that also helps with dma.
*/
if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
&& req->req.length > ep->desc->wMaxPacketSize))
&& req->req.length > le16_to_cpu
(ep->desc->wMaxPacketSize)))
return -EMSGSIZE;
#ifdef USE_DMA
// FIXME caller may already have done the dma mapping
if (ep->dma >= 0) {
_req->dma = dma_map_single(&dev->dev.dev,
_req->dma = dma_map_single(dev->dev,
_req->buf, _req->length,
((ep->bEndpointAddress & USB_DIR_IN) != 0)
? DMA_TO_DEVICE
......@@ -1017,11 +1027,21 @@ static int pxa2xx_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
unsigned long flags;
ep = container_of(_ep, struct pxa2xx_ep, ep);
req = container_of(_req, struct pxa2xx_request, req);
if (!_ep || !_req || ep->ep.name == ep0name)
if (!_ep || ep->ep.name == ep0name)
return -EINVAL;
local_irq_save(flags);
/* make sure it's actually queued on this endpoint */
list_for_each_entry (req, &ep->queue, queue) {
if (&req->req == _req)
break;
}
if (&req->req != _req) {
local_irq_restore(flags);
return -EINVAL;
}
#ifdef USE_DMA
if (ep->dma >= 0 && ep->queue.next == &req->queue && !ep->stopped) {
cancel_dma(ep);
......@@ -1034,13 +1054,10 @@ static int pxa2xx_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
}
} else
#endif
if (!list_empty(&req->queue))
done(ep, req, -ECONNRESET);
else
req = 0;
local_irq_restore(flags);
return req ? 0 : -EOPNOTSUPP;
local_irq_restore(flags);
return 0;
}
/*-------------------------------------------------------------------------*/
......@@ -1386,8 +1403,10 @@ static void udc_disable(struct pxa2xx_udc *dev)
udc_clear_mask_UDCCR(UDCCR_UDE);
#ifdef CONFIG_ARCH_PXA
/* Disable clock for USB device */
CKEN &= ~CKEN11_USB;
#endif
ep0_idle (dev);
dev->gadget.speed = USB_SPEED_UNKNOWN;
......@@ -1430,8 +1449,10 @@ static void udc_enable (struct pxa2xx_udc *dev)
{
udc_clear_mask_UDCCR(UDCCR_UDE);
#ifdef CONFIG_ARCH_PXA
/* Enable clock for USB device */
CKEN |= CKEN11_USB;
#endif
/* try to clear these bits before we enable the udc */
udc_ack_int_UDCCR(UDCCR_SUSIR|/*UDCCR_RSTIR|*/UDCCR_RESIR);
......@@ -1590,9 +1611,10 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
local_irq_disable();
udc_disable(dev);
stop_activity(dev, driver);
local_irq_enable();
driver->unbind(&dev->gadget);
dev->driver = 0;
local_irq_enable();
device_del (&dev->gadget.dev);
device_remove_file(dev->dev, &dev_attr_function);
......@@ -1776,7 +1798,6 @@ static void handle_ep0 (struct pxa2xx_udc *dev)
* else use AREN (later) not SA|OPR
* USIR0_IR0 acts edge sensitive
*/
dev->req_pending = 0;
}
break;
/* ... and here, even more ... */
......@@ -1853,6 +1874,7 @@ static void handle_ep0 (struct pxa2xx_udc *dev)
/* pxa210/250 erratum 131 for B0/B1 says RNE lies.
* still observed on a pxa255 a0.
*/
DBG(DBG_VERBOSE, "e131\n");
nuke(ep, -EPROTO);
/* read SETUP data, but don't trust it too much */
......@@ -2043,7 +2065,7 @@ pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r)
stop_activity (dev, dev->driver);
} else {
dev_info(&dev->gadget.dev, "USB reset\n");
INFO("USB reset\n");
dev->gadget.speed = USB_SPEED_FULL;
LED_CONNECTED_ON;
memset(&dev->stats, 0, sizeof dev->stats);
......@@ -2133,11 +2155,12 @@ static struct pxa2xx_udc memory = {
.maxpacket = BULK_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 1,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS1,
.reg_uddr = &UDDR1,
.reg_drcmr = &DRCMR25,
drcmr (25)
},
.ep[2] = {
.ep = {
......@@ -2146,12 +2169,13 @@ static struct pxa2xx_udc memory = {
.maxpacket = BULK_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = 2,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS2,
.reg_ubcr = &UBCR2,
.reg_uddr = &UDDR2,
.reg_drcmr = &DRCMR26,
drcmr (26)
},
#ifndef CONFIG_USB_PXA2XX_SMALL
.ep[3] = {
......@@ -2161,11 +2185,12 @@ static struct pxa2xx_udc memory = {
.maxpacket = ISO_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 3,
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS3,
.reg_uddr = &UDDR3,
.reg_drcmr = &DRCMR27,
drcmr (27)
},
.ep[4] = {
.ep = {
......@@ -2174,12 +2199,13 @@ static struct pxa2xx_udc memory = {
.maxpacket = ISO_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = 4,
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS4,
.reg_ubcr = &UBCR4,
.reg_uddr = &UDDR4,
.reg_drcmr = &DRCMR28,
drcmr (28)
},
.ep[5] = {
.ep = {
......@@ -2188,6 +2214,7 @@ static struct pxa2xx_udc memory = {
.maxpacket = INT_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = INT_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 5,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.reg_udccs = &UDCCS5,
......@@ -2202,11 +2229,12 @@ static struct pxa2xx_udc memory = {
.maxpacket = BULK_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 6,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS6,
.reg_uddr = &UDDR6,
.reg_drcmr = &DRCMR30,
drcmr (30)
},
.ep[7] = {
.ep = {
......@@ -2215,12 +2243,13 @@ static struct pxa2xx_udc memory = {
.maxpacket = BULK_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = 7,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS7,
.reg_ubcr = &UBCR7,
.reg_uddr = &UDDR7,
.reg_drcmr = &DRCMR31,
drcmr (31)
},
.ep[8] = {
.ep = {
......@@ -2229,11 +2258,12 @@ static struct pxa2xx_udc memory = {
.maxpacket = ISO_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 8,
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS8,
.reg_uddr = &UDDR8,
.reg_drcmr = &DRCMR32,
drcmr (32)
},
.ep[9] = {
.ep = {
......@@ -2242,12 +2272,13 @@ static struct pxa2xx_udc memory = {
.maxpacket = ISO_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = 9,
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS9,
.reg_ubcr = &UBCR9,
.reg_uddr = &UDDR9,
.reg_drcmr = &DRCMR33,
drcmr (33)
},
.ep[10] = {
.ep = {
......@@ -2256,6 +2287,7 @@ static struct pxa2xx_udc memory = {
.maxpacket = INT_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = INT_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 10,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.reg_udccs = &UDCCS10,
......@@ -2270,11 +2302,12 @@ static struct pxa2xx_udc memory = {
.maxpacket = BULK_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 11,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS11,
.reg_uddr = &UDDR11,
.reg_drcmr = &DRCMR35,
drcmr (35)
},
.ep[12] = {
.ep = {
......@@ -2283,12 +2316,13 @@ static struct pxa2xx_udc memory = {
.maxpacket = BULK_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = 12,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS12,
.reg_ubcr = &UBCR12,
.reg_uddr = &UDDR12,
.reg_drcmr = &DRCMR36,
drcmr (36)
},
.ep[13] = {
.ep = {
......@@ -2297,11 +2331,12 @@ static struct pxa2xx_udc memory = {
.maxpacket = ISO_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 13,
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS13,
.reg_uddr = &UDDR13,
.reg_drcmr = &DRCMR37,
drcmr (37)
},
.ep[14] = {
.ep = {
......@@ -2310,12 +2345,13 @@ static struct pxa2xx_udc memory = {
.maxpacket = ISO_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = 14,
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS14,
.reg_ubcr = &UBCR14,
.reg_uddr = &UDDR14,
.reg_drcmr = &DRCMR38,
drcmr (38)
},
.ep[15] = {
.ep = {
......@@ -2324,6 +2360,7 @@ static struct pxa2xx_udc memory = {
.maxpacket = INT_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = INT_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 15,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.reg_udccs = &UDCCS15,
......@@ -2333,8 +2370,15 @@ static struct pxa2xx_udc memory = {
};
#define CP15R0_VENDOR_MASK 0xffffe000
#if defined(CONFIG_ARCH_PXA)
#define CP15R0_XSCALE_VALUE 0x69052000 /* intel/arm/xscale */
#elif defined(CONFIG_ARCH_IXP425)
#define CP15R0_XSCALE_VALUE 0x69054000 /* intel/arm/ixp425 */
#endif
#define CP15R0_PROD_MASK 0x000003f0
#define PXA25x 0x00000100 /* and PXA26x */
#define PXA210 0x00000120
......@@ -2355,6 +2399,7 @@ static struct pxa2xx_udc memory = {
#define PXA210_B2 0x00000124
#define PXA210_B1 0x00000123
#define PXA210_B0 0x00000122
#define IXP425_A0 0x000001c1
/*
* probe - binds to the platform device
......@@ -2374,6 +2419,7 @@ static int __init pxa2xx_udc_probe(struct device *_dev)
/* trigger chiprev-specific logic */
switch (chiprev & CP15R0_PRODREV_MASK) {
#if defined(CONFIG_ARCH_PXA)
case PXA255_A0:
dev->has_cfr = 1;
break;
......@@ -2388,6 +2434,11 @@ static int __init pxa2xx_udc_probe(struct device *_dev)
/* fall through */
case PXA250_C0: case PXA210_C0:
break;
#elif defined(CONFIG_ARCH_IXP425)
case IXP425_A0:
out_dma = 0;
break;
#endif
default:
out_dma = 0;
printk(KERN_ERR "%s: unrecognized processor: %08x\n",
......@@ -2443,6 +2494,7 @@ static int __init pxa2xx_udc_probe(struct device *_dev)
}
dev->got_irq = 1;
#ifdef CONFIG_ARCH_LUBBOCK
if (machine_is_lubbock()) {
disable_irq(LUBBOCK_USB_DISC_IRQ);
retval = request_irq(LUBBOCK_USB_DISC_IRQ,
......@@ -2457,7 +2509,7 @@ static int __init pxa2xx_udc_probe(struct device *_dev)
}
dev->got_disc = 1;
}
#endif
create_proc_files();
return 0;
......
......@@ -52,8 +52,9 @@ struct pxa2xx_ep {
struct list_head queue;
unsigned long pio_irqs;
unsigned long dma_irqs;
int dma;
short dma;
unsigned short fifo_size;
u8 bEndpointAddress;
u8 bmAttributes;
......@@ -68,7 +69,12 @@ struct pxa2xx_ep {
volatile u32 *reg_udccs;
volatile u32 *reg_ubcr;
volatile u32 *reg_uddr;
#ifdef USE_DMA
volatile u32 *reg_drcmr;
#define drcmr(n) .reg_drcmr = & DRCMR ## n ,
#else
#define drcmr(n)
#endif
};
struct pxa2xx_request {
......@@ -181,14 +187,14 @@ static inline void make_usb_disappear(void)
{
if (!the_controller->mach->udc_command)
return;
the_controller->mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
}
static inline void let_usb_appear(void)
{
if (!the_controller->mach->udc_command)
return;
the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
the_controller->mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
}
/*-------------------------------------------------------------------------*/
......@@ -305,7 +311,7 @@ dump_state(struct pxa2xx_udc *dev)
#define DBG(lvl, stuff...) do{if ((lvl) <= UDC_DEBUG) DMSG(stuff);}while(0)
#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff)
#define INFO(stuff...) printk(KERN_INFO "udc: " stuff)
#endif /* __LINUX_USB_GADGET_PXA2XX_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment