diff options
Diffstat (limited to 'drivers/usb/musb/musb_gadget.c')
-rw-r--r-- | drivers/usb/musb/musb_gadget.c | 111 |
1 files changed, 35 insertions, 76 deletions
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 6aeb363e63e7..e81820370d6f 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1663,8 +1663,8 @@ static void musb_pullup(struct musb *musb, int is_on) /* FIXME if on, HdrcStart; if off, HdrcStop */ - dev_dbg(musb->controller, "gadget %s D+ pullup %s\n", - musb->gadget_driver->function, is_on ? "on" : "off"); + dev_dbg(musb->controller, "gadget D+ pullup %s\n", + is_on ? "on" : "off"); musb_writeb(musb->mregs, MUSB_POWER, power); } @@ -1698,6 +1698,8 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on) is_on = !!is_on; + pm_runtime_get_sync(musb->controller); + /* NOTE: this assumes we are sensing vbus; we'd rather * not pullup unless the B-session is active. */ @@ -1707,9 +1709,17 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on) musb_pullup(musb, is_on); } spin_unlock_irqrestore(&musb->lock, flags); + + pm_runtime_put(musb->controller); + return 0; } +static int musb_gadget_start(struct usb_gadget *g, + struct usb_gadget_driver *driver); +static int musb_gadget_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver); + static const struct usb_gadget_ops musb_gadget_operations = { .get_frame = musb_gadget_get_frame, .wakeup = musb_gadget_wakeup, @@ -1717,6 +1727,8 @@ static const struct usb_gadget_ops musb_gadget_operations = { /* .vbus_session = musb_gadget_vbus_session, */ .vbus_draw = musb_gadget_vbus_draw, .pullup = musb_gadget_pullup, + .udc_start = musb_gadget_start, + .udc_stop = musb_gadget_stop, }; /* ----------------------------------------------------------------------- */ @@ -1727,7 +1739,6 @@ static const struct usb_gadget_ops musb_gadget_operations = { * about there being only one external upstream port. It assumes * all peripheral ports are external... */ -static struct musb *the_gadget; static void musb_gadget_release(struct device *dev) { @@ -1814,9 +1825,6 @@ int __init musb_gadget_setup(struct musb *musb) * musb peripherals at the same time, only the bus lock * is probably held. */ - if (the_gadget) - return -EBUSY; - the_gadget = musb; musb->g.ops = &musb_gadget_operations; musb->g.is_dualspeed = 1; @@ -1840,18 +1848,24 @@ int __init musb_gadget_setup(struct musb *musb) status = device_register(&musb->g.dev); if (status != 0) { put_device(&musb->g.dev); - the_gadget = NULL; + return status; } + status = usb_add_gadget_udc(musb->controller, &musb->g); + if (status) + goto err; + + return 0; +err: + musb->g.dev.parent = NULL; + device_unregister(&musb->g.dev); return status; } void musb_gadget_cleanup(struct musb *musb) { - if (musb != the_gadget) - return; - - device_unregister(&musb->g.dev); - the_gadget = NULL; + usb_del_gadget_udc(&musb->g); + if (musb->g.dev.parent) + device_unregister(&musb->g.dev); } /* @@ -1863,59 +1877,30 @@ void musb_gadget_cleanup(struct musb *musb) * -ENOMEM no memory to perform the operation * * @param driver the gadget driver - * @param bind the driver's bind function * @return <0 if error, 0 if everything is fine */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +static int musb_gadget_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct musb *musb = the_gadget; + struct musb *musb = gadget_to_musb(g); unsigned long flags; int retval = -EINVAL; - if (!driver - || driver->speed != USB_SPEED_HIGH - || !bind || !driver->setup) + if (driver->speed != USB_SPEED_HIGH) goto err0; - /* driver must be initialized to support peripheral mode */ - if (!musb) { - dev_dbg(musb->controller, "no dev??\n"); - retval = -ENODEV; - goto err0; - } - pm_runtime_get_sync(musb->controller); dev_dbg(musb->controller, "registering driver %s\n", driver->function); - if (musb->gadget_driver) { - dev_dbg(musb->controller, "%s is already bound to %s\n", - musb_driver_name, - musb->gadget_driver->driver.name); - retval = -EBUSY; - goto err0; - } - - spin_lock_irqsave(&musb->lock, flags); + musb->softconnect = 0; musb->gadget_driver = driver; - musb->g.dev.driver = &driver->driver; - driver->driver.bus = NULL; - musb->softconnect = 1; - spin_unlock_irqrestore(&musb->lock, flags); - - retval = bind(&musb->g); - if (retval) { - dev_dbg(musb->controller, "bind to driver %s failed --> %d\n", - driver->driver.name, retval); - goto err1; - } spin_lock_irqsave(&musb->lock, flags); + musb->is_active = 1; otg_set_peripheral(musb->xceiv, &musb->g); musb->xceiv->state = OTG_STATE_B_IDLE; - musb->is_active = 1; /* * FIXME this ignores the softconnect flag. Drivers are @@ -1927,8 +1912,6 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, if (!is_otg_enabled(musb)) musb_start(musb); - otg_set_peripheral(musb->xceiv, &musb->g); - spin_unlock_irqrestore(&musb->lock, flags); if (is_otg_enabled(musb)) { @@ -1960,15 +1943,9 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, err2: if (!is_otg_enabled(musb)) musb_stop(musb); - -err1: - musb->gadget_driver = NULL; - musb->g.dev.driver = NULL; - err0: return retval; } -EXPORT_SYMBOL(usb_gadget_probe_driver); static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver) { @@ -2018,17 +1995,12 @@ static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver) * * @param driver the gadget driver to unregister */ -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int musb_gadget_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct musb *musb = the_gadget; + struct musb *musb = gadget_to_musb(g); unsigned long flags; - if (!driver || !driver->unbind || !musb) - return -EINVAL; - - if (!musb->gadget_driver) - return -EINVAL; - if (musb->xceiv->last_event == USB_EVENT_NONE) pm_runtime_get_sync(musb->controller); @@ -2039,9 +2011,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) spin_lock_irqsave(&musb->lock, flags); -#ifdef CONFIG_USB_MUSB_OTG musb_hnp_stop(musb); -#endif (void) musb_gadget_vbus_draw(&musb->g, 0); @@ -2051,13 +2021,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) dev_dbg(musb->controller, "unregistering driver %s\n", driver->function); - spin_unlock_irqrestore(&musb->lock, flags); - driver->unbind(&musb->g); - spin_lock_irqsave(&musb->lock, flags); - - musb->gadget_driver = NULL; - musb->g.dev.driver = NULL; - musb->is_active = 0; musb_platform_try_idle(musb, 0); spin_unlock_irqrestore(&musb->lock, flags); @@ -2077,8 +2040,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); - /* ----------------------------------------------------------------------- */ @@ -2164,7 +2125,6 @@ void musb_g_disconnect(struct musb *musb) switch (musb->xceiv->state) { default: -#ifdef CONFIG_USB_MUSB_OTG dev_dbg(musb->controller, "Unhandled disconnect %s, setting a_idle\n", otg_state_string(musb->xceiv->state)); musb->xceiv->state = OTG_STATE_A_IDLE; @@ -2176,7 +2136,6 @@ void musb_g_disconnect(struct musb *musb) break; case OTG_STATE_B_WAIT_ACON: case OTG_STATE_B_HOST: -#endif case OTG_STATE_B_PERIPHERAL: case OTG_STATE_B_IDLE: musb->xceiv->state = OTG_STATE_B_IDLE; |