use new interfaces from udc-core on goku controller driver. Signed-off-by: Felipe Balbi <balbi@xxxxxx> --- drivers/usb/gadget/Kconfig | 2 +- drivers/usb/gadget/goku_udc.c | 369 ++++++++++++++++++----------------------- drivers/usb/gadget/goku_udc.h | 4 +- 3 files changed, 162 insertions(+), 213 deletions(-) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index e6d4f2a..8628d4e 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -19,7 +19,7 @@ config USB_UDC_CORE menuconfig USB_GADGET tristate "USB Gadget Support" select USB_UDC_CORE if (USB_GADGET_MUSB_HDRC || USB_GADGET_AMD5536UDC) - select USB_UDC_CORE if (USB_GADGET_AT91) + select USB_UDC_CORE if (USB_GADGET_AT91 || USB_GADGET_GOKU) help USB is a master/slave protocol, organized with one master host (such as a PC) controlling up to 127 peripheral devices. diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 1088d08..4e73d1f 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -108,7 +108,7 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) dev = ep->dev; if (ep == &dev->ep[0]) return -EINVAL; - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) + if (!dev->udc.driver || dev->gadget.speed == USB_SPEED_UNKNOWN) return -ESHUTDOWN; if (ep->num != usb_endpoint_num(desc)) return -EINVAL; @@ -727,7 +727,7 @@ goku_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) if (unlikely(!_ep || (!ep->desc && ep->num != 0))) return -EINVAL; dev = ep->dev; - if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) + if (unlikely(!dev->udc.driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) return -ESHUTDOWN; /* can't touch registers when suspended */ @@ -819,7 +819,7 @@ static int goku_dequeue(struct usb_ep *_ep, struct usb_request *_req) if (!_ep || !_req || (!ep->desc && ep->num != 0)) return -EINVAL; dev = ep->dev; - if (!dev->driver) + if (!dev->udc.driver) return -ESHUTDOWN; /* we can't touch (dma) registers when suspended */ @@ -995,8 +995,146 @@ static int goku_get_frame(struct usb_gadget *_gadget) return -EOPNOTSUPP; } +static void udc_reset(struct goku_udc *dev) +{ + struct goku_udc_regs __iomem *regs = dev->regs; + + writel(0, ®s->power_detect); + writel(0, ®s->int_enable); + readl(®s->int_enable); + dev->int_enable = 0; + + /* deassert reset, leave USB D+ at hi-Z (no pullup) + * don't let INT_PWRDETECT sequence begin + */ + udelay(250); + writel(PW_RESETB, ®s->power_detect); + readl(®s->int_enable); +} + +static void udc_reinit (struct goku_udc *dev) +{ + static char *names [] = { "ep0", "ep1-bulk", "ep2-bulk", "ep3-bulk" }; + + unsigned i; + + INIT_LIST_HEAD (&dev->gadget.ep_list); + dev->gadget.ep0 = &dev->ep [0].ep; + dev->gadget.speed = USB_SPEED_UNKNOWN; + dev->ep0state = EP0_DISCONNECT; + dev->irqs = 0; + + for (i = 0; i < 4; i++) { + struct goku_ep *ep = &dev->ep[i]; + + ep->num = i; + ep->ep.name = names[i]; + ep->reg_fifo = &dev->regs->ep_fifo [i]; + ep->reg_status = &dev->regs->ep_status [i]; + ep->reg_mode = &dev->regs->ep_mode[i]; + + ep->ep.ops = &goku_ep_ops; + list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list); + ep->dev = dev; + INIT_LIST_HEAD (&ep->queue); + + ep_reset(NULL, ep); + } + + dev->ep[0].reg_mode = NULL; + dev->ep[0].ep.maxpacket = MAX_EP0_SIZE; + list_del_init (&dev->ep[0].ep.ep_list); +} + +static void ep0_start(struct goku_udc *dev) +{ + struct goku_udc_regs __iomem *regs = dev->regs; + unsigned i; + + VDBG(dev, "%s\n", __func__); + + udc_reset(dev); + udc_reinit (dev); + //writel(MST_EOPB_ENA | MST_TIMEOUT_ENA, ®s->dma_master); + + /* hw handles set_address, set_feature, get_status; maybe more */ + writel( G_REQMODE_SET_INTF | G_REQMODE_GET_INTF + | G_REQMODE_SET_CONF | G_REQMODE_GET_CONF + | G_REQMODE_GET_DESC + | G_REQMODE_CLEAR_FEAT + , ®s->reqmode); + + for (i = 0; i < 4; i++) + dev->ep[i].irqs = 0; + + /* can't modify descriptors after writing UsbReady */ + for (i = 0; i < DESC_LEN; i++) + writel(0, ®s->descriptors[i]); + writel(0, ®s->UsbReady); + + /* expect ep0 requests when the host drops reset */ + writel(PW_RESETB | PW_PULLUP, ®s->power_detect); + dev->int_enable = INT_DEVWIDE | INT_EP0; + writel(dev->int_enable, &dev->regs->int_enable); + readl(®s->int_enable); + dev->gadget.speed = USB_SPEED_FULL; + dev->ep0state = EP0_IDLE; +} + +static void udc_enable(struct goku_udc *dev) +{ + /* start enumeration now, or after power detect irq */ + if (readl(&dev->regs->power_detect) & PW_DETECT) + ep0_start(dev); + else { + DBG(dev, "%s\n", __func__); + dev->int_enable = INT_PWRDETECT; + writel(dev->int_enable, &dev->regs->int_enable); + } +} + +/* when a driver is successfully registered, it will receive + * control requests including set_configuration(), which enables + * non-control requests. then usb traffic follows until a + * disconnect is reported. then a host may connect again, or + * the driver might get unbound. + */ +static int goku_start(struct usb_gadget *gadget) +{ + struct goku_udc *dev = container_of(gadget, struct goku_udc, gadget); + + udc_enable(dev); + + return 0; +} + +static void +stop_activity(struct goku_udc *dev) +{ + unsigned i; + + DBG (dev, "%s\n", __func__); + + /* disconnect gadget driver after quiesceing hw and the driver */ + udc_reset (dev); + for (i = 0; i < 4; i++) + nuke(&dev->ep [i], -ESHUTDOWN); +} + +static void goku_stop(struct usb_gadget *gadget) +{ + struct goku_udc *dev = container_of(gadget, struct goku_udc, gadget); + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + stop_activity(dev); + spin_unlock_irqrestore(&dev->lock, flags); +} + static const struct usb_gadget_ops goku_ops = { .get_frame = goku_get_frame, + .start = goku_start, + .stop = goku_stop, // no remote wakeup // not selfpowered }; @@ -1087,7 +1225,7 @@ udc_proc_read(char *buffer, char **start, off_t off, int count, "\n", pci_name(dev->pdev), driver_desc, driver_name, DRIVER_VERSION, dmastr(), - dev->driver ? dev->driver->driver.name : "(none)", + dev->udc.driver ? dev->udc.driver->driver.name : "(none)", is_usb_connected ? ((tmp & PW_PULLUP) ? "full speed" : "powered") : "disconnected", @@ -1109,7 +1247,7 @@ udc_proc_read(char *buffer, char **start, off_t off, int count, dump_intmask("int_status", readl(®s->int_status), &next, &size); dump_intmask("int_enable", readl(®s->int_enable), &next, &size); - if (!is_usb_connected || !dev->driver || (tmp & PW_PULLUP) == 0) + if (!is_usb_connected || !dev->udc.driver || (tmp & PW_PULLUP) == 0) goto done; /* registers for (active) device and ep0 */ @@ -1230,106 +1368,6 @@ done: /*-------------------------------------------------------------------------*/ -static void udc_reinit (struct goku_udc *dev) -{ - static char *names [] = { "ep0", "ep1-bulk", "ep2-bulk", "ep3-bulk" }; - - unsigned i; - - INIT_LIST_HEAD (&dev->gadget.ep_list); - dev->gadget.ep0 = &dev->ep [0].ep; - dev->gadget.speed = USB_SPEED_UNKNOWN; - dev->ep0state = EP0_DISCONNECT; - dev->irqs = 0; - - for (i = 0; i < 4; i++) { - struct goku_ep *ep = &dev->ep[i]; - - ep->num = i; - ep->ep.name = names[i]; - ep->reg_fifo = &dev->regs->ep_fifo [i]; - ep->reg_status = &dev->regs->ep_status [i]; - ep->reg_mode = &dev->regs->ep_mode[i]; - - ep->ep.ops = &goku_ep_ops; - list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list); - ep->dev = dev; - INIT_LIST_HEAD (&ep->queue); - - ep_reset(NULL, ep); - } - - dev->ep[0].reg_mode = NULL; - dev->ep[0].ep.maxpacket = MAX_EP0_SIZE; - list_del_init (&dev->ep[0].ep.ep_list); -} - -static void udc_reset(struct goku_udc *dev) -{ - struct goku_udc_regs __iomem *regs = dev->regs; - - writel(0, ®s->power_detect); - writel(0, ®s->int_enable); - readl(®s->int_enable); - dev->int_enable = 0; - - /* deassert reset, leave USB D+ at hi-Z (no pullup) - * don't let INT_PWRDETECT sequence begin - */ - udelay(250); - writel(PW_RESETB, ®s->power_detect); - readl(®s->int_enable); -} - -static void ep0_start(struct goku_udc *dev) -{ - struct goku_udc_regs __iomem *regs = dev->regs; - unsigned i; - - VDBG(dev, "%s\n", __func__); - - udc_reset(dev); - udc_reinit (dev); - //writel(MST_EOPB_ENA | MST_TIMEOUT_ENA, ®s->dma_master); - - /* hw handles set_address, set_feature, get_status; maybe more */ - writel( G_REQMODE_SET_INTF | G_REQMODE_GET_INTF - | G_REQMODE_SET_CONF | G_REQMODE_GET_CONF - | G_REQMODE_GET_DESC - | G_REQMODE_CLEAR_FEAT - , ®s->reqmode); - - for (i = 0; i < 4; i++) - dev->ep[i].irqs = 0; - - /* can't modify descriptors after writing UsbReady */ - for (i = 0; i < DESC_LEN; i++) - writel(0, ®s->descriptors[i]); - writel(0, ®s->UsbReady); - - /* expect ep0 requests when the host drops reset */ - writel(PW_RESETB | PW_PULLUP, ®s->power_detect); - dev->int_enable = INT_DEVWIDE | INT_EP0; - writel(dev->int_enable, &dev->regs->int_enable); - readl(®s->int_enable); - dev->gadget.speed = USB_SPEED_FULL; - dev->ep0state = EP0_IDLE; -} - -static void udc_enable(struct goku_udc *dev) -{ - /* start enumeration now, or after power detect irq */ - if (readl(&dev->regs->power_detect) & PW_DETECT) - ep0_start(dev); - else { - DBG(dev, "%s\n", __func__); - dev->int_enable = INT_PWRDETECT; - writel(dev->int_enable, &dev->regs->int_enable); - } -} - -/*-------------------------------------------------------------------------*/ - /* keeping it simple: * - one bus driver, initted first; * - one function driver, initted second @@ -1337,99 +1375,6 @@ static void udc_enable(struct goku_udc *dev) static struct goku_udc *the_controller; -/* when a driver is successfully registered, it will receive - * control requests including set_configuration(), which enables - * non-control requests. then usb traffic follows until a - * disconnect is reported. then a host may connect again, or - * the driver might get unbound. - */ -int usb_gadget_register_driver(struct usb_gadget_driver *driver) -{ - struct goku_udc *dev = the_controller; - int retval; - - if (!driver - || driver->speed < USB_SPEED_FULL - || !driver->bind - || !driver->disconnect - || !driver->setup) - return -EINVAL; - if (!dev) - return -ENODEV; - if (dev->driver) - return -EBUSY; - - /* hook up the driver */ - driver->driver.bus = NULL; - dev->driver = driver; - dev->gadget.dev.driver = &driver->driver; - retval = driver->bind(&dev->gadget); - if (retval) { - DBG(dev, "bind to driver %s --> error %d\n", - driver->driver.name, retval); - dev->driver = NULL; - dev->gadget.dev.driver = NULL; - return retval; - } - - /* then enable host detection and ep0; and we're ready - * for set_configuration as well as eventual disconnect. - */ - udc_enable(dev); - - DBG(dev, "registered gadget driver '%s'\n", driver->driver.name); - return 0; -} -EXPORT_SYMBOL(usb_gadget_register_driver); - -static void -stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver) -{ - unsigned i; - - DBG (dev, "%s\n", __func__); - - if (dev->gadget.speed == USB_SPEED_UNKNOWN) - driver = NULL; - - /* disconnect gadget driver after quiesceing hw and the driver */ - udc_reset (dev); - for (i = 0; i < 4; i++) - nuke(&dev->ep [i], -ESHUTDOWN); - if (driver) { - spin_unlock(&dev->lock); - driver->disconnect(&dev->gadget); - spin_lock(&dev->lock); - } - - if (dev->driver) - udc_enable(dev); -} - -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) -{ - struct goku_udc *dev = the_controller; - unsigned long flags; - - if (!dev) - return -ENODEV; - if (!driver || driver != dev->driver || !driver->unbind) - return -EINVAL; - - spin_lock_irqsave(&dev->lock, flags); - dev->driver = NULL; - stop_activity(dev, driver); - spin_unlock_irqrestore(&dev->lock, flags); - - driver->unbind(&dev->gadget); - dev->gadget.dev.driver = NULL; - - DBG(dev, "unregistered driver '%s'\n", driver->driver.name); - return 0; -} -EXPORT_SYMBOL(usb_gadget_unregister_driver); - - /*-------------------------------------------------------------------------*/ static void ep0_setup(struct goku_udc *dev) @@ -1525,7 +1470,7 @@ succeed: * it may respond after this irq handler returns. */ spin_unlock (&dev->lock); - tmp = dev->driver->setup(&dev->gadget, &ctrl); + tmp = dev->udc.driver->setup(&dev->gadget, &ctrl); spin_lock (&dev->lock); if (unlikely(tmp < 0)) { stall: @@ -1567,11 +1512,11 @@ rescan: if (unlikely(stat & INT_DEVWIDE)) { if (stat & INT_SYSERROR) { ERROR(dev, "system error\n"); - stop_activity(dev, dev->driver); + stop_activity(dev); stat = 0; handled = 1; // FIXME have a neater way to prevent re-enumeration - dev->driver = NULL; + dev->udc.driver = NULL; goto done; } if (stat & INT_PWRDETECT) { @@ -1582,7 +1527,7 @@ rescan: } else { DBG(dev, "disconnect\n"); if (dev->gadget.speed == USB_SPEED_FULL) - stop_activity(dev, dev->driver); + stop_activity(dev); dev->ep0state = EP0_DISCONNECT; dev->int_enable = INT_DEVWIDE; writel(dev->int_enable, &dev->regs->int_enable); @@ -1604,10 +1549,10 @@ rescan: DBG(dev, "USB suspend\n"); dev->ep0state = EP0_SUSPEND; if (dev->gadget.speed != USB_SPEED_UNKNOWN - && dev->driver - && dev->driver->suspend) { + && dev->udc.driver + && dev->udc.driver->suspend) { spin_unlock(&dev->lock); - dev->driver->suspend(&dev->gadget); + dev->udc.driver->suspend(&dev->gadget); spin_lock(&dev->lock); } } else { @@ -1619,10 +1564,10 @@ rescan: DBG(dev, "USB resume\n"); dev->ep0state = EP0_IDLE; if (dev->gadget.speed != USB_SPEED_UNKNOWN - && dev->driver - && dev->driver->resume) { + && dev->udc.driver + && dev->udc.driver->resume) { spin_unlock(&dev->lock); - dev->driver->resume(&dev->gadget); + dev->udc.driver->resume(&dev->gadget); spin_lock(&dev->lock); } } @@ -1631,7 +1576,7 @@ pm_next: if (stat & INT_USBRESET) { /* hub reset done */ ACK(INT_USBRESET); INFO(dev, "USB reset done, gadget %s\n", - dev->driver->driver.name); + dev->udc.driver->driver.name); } // and INT_ERR on some endpoint's crc/bitstuff/... problem } @@ -1728,7 +1673,7 @@ static void goku_remove(struct pci_dev *pdev) DBG(dev, "%s\n", __func__); - BUG_ON(dev->driver); + BUG_ON(dev->udc.driver); #ifdef CONFIG_USB_GADGET_DEBUG_FILES remove_proc_entry(proc_node_name, NULL); @@ -1846,7 +1791,9 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* done */ the_controller = dev; - retval = device_register(&dev->gadget.dev); + dev->udc.gadget = &dev->gadget; + + retval = usb_add_udc(&pdev->dev, &dev->udc); if (retval == 0) return 0; diff --git a/drivers/usb/gadget/goku_udc.h b/drivers/usb/gadget/goku_udc.h index 566cb23..8e0153a 100644 --- a/drivers/usb/gadget/goku_udc.h +++ b/drivers/usb/gadget/goku_udc.h @@ -11,6 +11,8 @@ * warranty of any kind, whether express or implied. */ +#include <linux/usb/udc.h> + /* * PCI BAR 0 points to these registers. */ @@ -241,10 +243,10 @@ enum ep0state { struct goku_udc { /* each pci device provides one gadget, several endpoints */ + struct usb_udc udc; struct usb_gadget gadget; spinlock_t lock; struct goku_ep ep[4]; - struct usb_gadget_driver *driver; enum ep0state ep0state; unsigned got_irq:1, -- 1.7.3.rc0.35.g8ac8c -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html