/*
* linux/drivers/usb/gadget/pxa2xx_udc.c
- * Intel PXA2xx and IXP4xx on-chip full speed USB device controllers
+ * Intel PXA25x and IXP4xx on-chip full speed USB device controllers
*
* Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker)
* Copyright (C) 2003 Robert Schwebel, Pengutronix
/*
- * This driver handles the USB Device Controller (UDC) in Intel's PXA 2xx
+ * This driver handles the USB Device Controller (UDC) in Intel's PXA 25x
* series processors. The UDC for the IXP 4xx series is very similar.
* There are fifteen endpoints, in addition to ep0.
*
* pxa250 a0/a1 b0/b1/b2 sure act like they're still there.
*/
-#define DRIVER_VERSION "14-Dec-2003"
-#define DRIVER_DESC "PXA 2xx USB Device Controller driver"
+#define DRIVER_VERSION "4-May-2005"
+#define DRIVER_DESC "PXA 25x USB Device Controller driver"
static const char driver_name [] = "pxa2xx_udc";
static int pxa2xx_ep_disable (struct usb_ep *_ep)
{
struct pxa2xx_ep *ep;
+ unsigned long flags;
ep = container_of (_ep, struct pxa2xx_ep, ep);
if (!_ep || !ep->desc) {
_ep ? ep->ep.name : NULL);
return -EINVAL;
}
+ local_irq_save(flags);
+
nuke (ep, -ESHUTDOWN);
#ifdef USE_DMA
ep->desc = NULL;
ep->stopped = 1;
+ local_irq_restore(flags);
DBG(DBG_VERBOSE, "%s disabled\n", _ep->name);
return 0;
}
kick_dma(ep, req);
#endif
/* can the FIFO can satisfy the request immediately? */
- } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0
- && (*ep->reg_udccs & UDCCS_BI_TFS) != 0
- && write_fifo(ep, req)) {
- req = NULL;
+ } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) {
+ if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0
+ && write_fifo(ep, req))
+ req = NULL;
} else if ((*ep->reg_udccs & UDCCS_BO_RFS) != 0
&& read_fifo(ep, req)) {
req = NULL;
"%s version: %s\nGadget driver: %s\nHost %s\n\n",
driver_name, DRIVER_VERSION SIZE_STR DMASTR,
dev->driver ? dev->driver->driver.name : "(none)",
- is_usb_connected() ? "full speed" : "disconnected");
+ is_vbus_present() ? "full speed" : "disconnected");
size -= t;
next += t;
next += t;
}
- if (!is_usb_connected() || !dev->driver)
+ if (!is_vbus_present() || !dev->driver)
goto done;
t = scnprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n",
UFNRH = UFNRH_SIM;
/* if hardware supports it, disconnect from usb */
- make_usb_disappear();
+ pullup_off();
udc_clear_mask_UDCCR(UDCCR_UDE);
UICR0 &= ~UICR0_IM0;
/* if hardware supports it, pullup D+ and wait for reset */
- let_usb_appear();
+ pullup_on();
}
if (unlikely(udccr & UDCCR_SUSIR)) {
udc_ack_int_UDCCR(UDCCR_SUSIR);
handled = 1;
- DBG(DBG_VERBOSE, "USB suspend%s\n", is_usb_connected()
+ DBG(DBG_VERBOSE, "USB suspend%s\n", is_vbus_present()
? "" : "+disconnect");
- if (!is_usb_connected())
+ if (!is_vbus_present())
stop_activity(dev, dev->driver);
else if (dev->gadget.speed != USB_SPEED_UNKNOWN
&& dev->driver
if (dev->gadget.speed != USB_SPEED_UNKNOWN
&& dev->driver
&& dev->driver->resume
- && is_usb_connected())
+ && is_vbus_present())
dev->driver->resume(&dev->gadget);
}
udc_disable(dev);
udc_reinit(dev);
- dev->vbus = is_usb_connected();
+ dev->vbus = is_vbus_present();
/* irq setup after old hardware state is cleaned up */
retval = request_irq(IRQ_USB, pxa2xx_udc_irq,
return 0;
}
+
+static void pxa2xx_udc_shutdown(struct device *_dev)
+{
+ pullup_off();
+}
+
static int __exit pxa2xx_udc_remove(struct device *_dev)
{
struct pxa2xx_udc *dev = dev_get_drvdata(_dev);
.name = "pxa2xx-udc",
.bus = &platform_bus_type,
.probe = pxa2xx_udc_probe,
+ .shutdown = pxa2xx_udc_shutdown,
.remove = __exit_p(pxa2xx_udc_remove),
.suspend = pxa2xx_udc_suspend,
.resume = pxa2xx_udc_resume,
static struct pxa2xx_udc *the_controller;
-/* one GPIO should be used to detect host disconnect */
-static inline int is_usb_connected(void)
+/* one GPIO should be used to detect VBUS from the host */
+static inline int is_vbus_present(void)
{
if (!the_controller->mach->udc_is_connected)
return 1;
return the_controller->mach->udc_is_connected();
}
-/* one GPIO should force the host to see this device (or not) */
-static inline void make_usb_disappear(void)
+/* one GPIO should control a D+ pullup, so host sees this device (or not) */
+static inline void pullup_off(void)
{
if (!the_controller->mach->udc_command)
return;
the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
}
-static inline void let_usb_appear(void)
+static inline void pullup_on(void)
{
if (!the_controller->mach->udc_command)
return;