diff options
Diffstat (limited to 'drivers/usb/musb/musb_gadget.c')
| -rw-r--r-- | drivers/usb/musb/musb_gadget.c | 103 |
1 files changed, 52 insertions, 51 deletions
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 51274b87f46c..d666c4292753 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -14,6 +14,7 @@ #include <linux/module.h> #include <linux/smp.h> #include <linux/spinlock.h> +#include <linux/string_choices.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/slab.h> @@ -760,6 +761,9 @@ static void rxstate(struct musb *musb, struct musb_request *req) musb_writew(epio, MUSB_RXCSR, csr); buffer_aint_mapped: + fifo_count = min_t(unsigned int, + request->length - request->actual, + (unsigned int)fifo_count); musb_read_fifo(musb_ep->hw_ep, fifo_count, (u8 *) (request->buf + request->actual)); request->actual += fifo_count; @@ -1127,7 +1131,7 @@ static int musb_gadget_disable(struct usb_ep *ep) struct usb_request *musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) { struct musb_ep *musb_ep = to_musb_ep(ep); - struct musb_request *request = NULL; + struct musb_request *request; request = kzalloc(sizeof *request, gfp_flags); if (!request) @@ -1153,26 +1157,24 @@ void musb_free_request(struct usb_ep *ep, struct usb_request *req) kfree(request); } -static LIST_HEAD(buffers); - -struct free_record { - struct list_head list; - struct device *dev; - unsigned bytes; - dma_addr_t dma; -}; - /* * Context: controller locked, IRQs blocked. */ void musb_ep_restart(struct musb *musb, struct musb_request *req) { + u16 csr; + void __iomem *epio = req->ep->hw_ep->regs; + trace_musb_req_start(req); musb_ep_select(musb->mregs, req->epnum); - if (req->tx) + if (req->tx) { txstate(musb, req); - else - rxstate(musb, req); + } else { + csr = musb_readw(epio, MUSB_RXCSR); + csr |= MUSB_RXCSR_FLUSHFIFO | MUSB_RXCSR_P_WZC_BITS; + musb_writew(epio, MUSB_RXCSR, csr); + musb_writew(epio, MUSB_RXCSR, csr); + } } static int musb_ep_restart_resume_work(struct musb *musb, void *data) @@ -1256,7 +1258,6 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, unlock: spin_unlock_irqrestore(&musb->lock, lockflags); - pm_runtime_mark_last_busy(musb->controller); pm_runtime_put_autosuspend(musb->controller); return status; @@ -1520,7 +1521,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget) spin_lock_irqsave(&musb->lock, flags); - switch (musb->xceiv->otg->state) { + switch (musb_get_state(musb)) { case OTG_STATE_B_PERIPHERAL: /* NOTE: OTG state machine doesn't include B_SUSPENDED; * that's part of the standard usb 1.1 state machine, and @@ -1549,9 +1550,11 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget) break; } - spin_unlock_irqrestore(&musb->lock, flags); - otg_start_srp(musb->xceiv->otg); - spin_lock_irqsave(&musb->lock, flags); + if (musb->xceiv) { + spin_unlock_irqrestore(&musb->lock, flags); + otg_start_srp(musb->xceiv->otg); + spin_lock_irqsave(&musb->lock, flags); + } /* Block idling for at least 1s */ musb_platform_try_idle(musb, @@ -1561,7 +1564,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget) goto done; default: musb_dbg(musb, "Unhandled wake: %s", - usb_otg_state_string(musb->xceiv->otg->state)); + musb_otg_state_string(musb)); goto done; } @@ -1603,7 +1606,7 @@ static void musb_pullup(struct musb *musb, int is_on) /* FIXME if on, HdrcStart; if off, HdrcStop */ musb_dbg(musb, "gadget D+ pullup %s", - is_on ? "on" : "off"); + str_on_off(is_on)); musb_writeb(musb->mregs, MUSB_POWER, power); } @@ -1625,8 +1628,6 @@ static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) { struct musb *musb = gadget_to_musb(gadget); - if (!musb->xceiv->set_power) - return -EOPNOTSUPP; return usb_phy_set_power(musb->xceiv, mA); } @@ -1640,7 +1641,6 @@ static void musb_gadget_work(struct work_struct *work) spin_lock_irqsave(&musb->lock, flags); musb_pullup(musb, musb->softconnect); spin_unlock_irqrestore(&musb->lock, flags); - pm_runtime_mark_last_busy(musb->controller); pm_runtime_put_autosuspend(musb->controller); } @@ -1741,7 +1741,6 @@ static inline void musb_g_init_endpoints(struct musb *musb) { u8 epnum; struct musb_hw_ep *hw_ep; - unsigned count = 0; /* initialize endpoint list just once */ INIT_LIST_HEAD(&(musb->g.ep_list)); @@ -1751,17 +1750,14 @@ static inline void musb_g_init_endpoints(struct musb *musb) epnum++, hw_ep++) { if (hw_ep->is_shared_fifo /* || !epnum */) { init_peripheral_ep(musb, &hw_ep->ep_in, epnum, 0); - count++; } else { if (hw_ep->max_packet_sz_tx) { init_peripheral_ep(musb, &hw_ep->ep_in, epnum, 1); - count++; } if (hw_ep->max_packet_sz_rx) { init_peripheral_ep(musb, &hw_ep->ep_out, epnum, 0); - count++; } } } @@ -1784,7 +1780,7 @@ int musb_gadget_setup(struct musb *musb) musb->g.speed = USB_SPEED_UNKNOWN; MUSB_DEV_MODE(musb); - musb->xceiv->otg->state = OTG_STATE_B_IDLE; + musb_set_state(musb, OTG_STATE_B_IDLE); /* this "gadget" abstracts/virtualizes the controller */ musb->g.name = musb_driver_name; @@ -1831,7 +1827,6 @@ static int musb_gadget_start(struct usb_gadget *g, struct usb_gadget_driver *driver) { struct musb *musb = gadget_to_musb(g); - struct usb_otg *otg = musb->xceiv->otg; unsigned long flags; int retval = 0; @@ -1848,8 +1843,12 @@ static int musb_gadget_start(struct usb_gadget *g, spin_lock_irqsave(&musb->lock, flags); musb->is_active = 1; - otg_set_peripheral(otg, &musb->g); - musb->xceiv->otg->state = OTG_STATE_B_IDLE; + if (musb->xceiv) + otg_set_peripheral(musb->xceiv->otg, &musb->g); + else + phy_set_mode(musb->phy, PHY_MODE_USB_DEVICE); + + musb_set_state(musb, OTG_STATE_B_IDLE); spin_unlock_irqrestore(&musb->lock, flags); musb_start(musb); @@ -1858,10 +1857,9 @@ static int musb_gadget_start(struct usb_gadget *g, * handles power budgeting ... this way also * ensures HdrcStart is indirectly called. */ - if (musb->xceiv->last_event == USB_EVENT_ID) + if (musb->xceiv && musb->xceiv->last_event == USB_EVENT_ID) musb_platform_set_vbus(musb, 1); - pm_runtime_mark_last_busy(musb->controller); pm_runtime_put_autosuspend(musb->controller); return 0; @@ -1894,9 +1892,13 @@ static int musb_gadget_stop(struct usb_gadget *g) (void) musb_gadget_vbus_draw(&musb->g, 0); - musb->xceiv->otg->state = OTG_STATE_UNDEFINED; + musb_set_state(musb, OTG_STATE_UNDEFINED); musb_stop(musb); - otg_set_peripheral(musb->xceiv->otg, NULL); + + if (musb->xceiv) + otg_set_peripheral(musb->xceiv->otg, NULL); + else + phy_set_mode(musb->phy, PHY_MODE_INVALID); musb->is_active = 0; musb->gadget_driver = NULL; @@ -1908,11 +1910,9 @@ static int musb_gadget_stop(struct usb_gadget *g) * gadget driver here and have everything work; * that currently misbehaves. */ + usb_gadget_set_state(g, USB_STATE_NOTATTACHED); /* Force check of devctl register for PM runtime */ - schedule_delayed_work(&musb->irq_work, 0); - - pm_runtime_mark_last_busy(musb->controller); pm_runtime_put_autosuspend(musb->controller); return 0; @@ -1925,7 +1925,7 @@ static int musb_gadget_stop(struct usb_gadget *g) void musb_g_resume(struct musb *musb) { musb->is_suspended = 0; - switch (musb->xceiv->otg->state) { + switch (musb_get_state(musb)) { case OTG_STATE_B_IDLE: break; case OTG_STATE_B_WAIT_ACON: @@ -1939,7 +1939,7 @@ void musb_g_resume(struct musb *musb) break; default: WARNING("unhandled RESUME transition (%s)\n", - usb_otg_state_string(musb->xceiv->otg->state)); + musb_otg_state_string(musb)); } } @@ -1951,10 +1951,10 @@ void musb_g_suspend(struct musb *musb) devctl = musb_readb(musb->mregs, MUSB_DEVCTL); musb_dbg(musb, "musb_g_suspend: devctl %02x", devctl); - switch (musb->xceiv->otg->state) { + switch (musb_get_state(musb)) { case OTG_STATE_B_IDLE: if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) - musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; + musb_set_state(musb, OTG_STATE_B_PERIPHERAL); break; case OTG_STATE_B_PERIPHERAL: musb->is_suspended = 1; @@ -1969,7 +1969,7 @@ void musb_g_suspend(struct musb *musb) * A_PERIPHERAL may need care too */ WARNING("unhandled SUSPEND transition (%s)", - usb_otg_state_string(musb->xceiv->otg->state)); + musb_otg_state_string(musb)); } } @@ -2000,22 +2000,23 @@ void musb_g_disconnect(struct musb *musb) spin_lock(&musb->lock); } - switch (musb->xceiv->otg->state) { + switch (musb_get_state(musb)) { default: musb_dbg(musb, "Unhandled disconnect %s, setting a_idle", - usb_otg_state_string(musb->xceiv->otg->state)); - musb->xceiv->otg->state = OTG_STATE_A_IDLE; + musb_otg_state_string(musb)); + musb_set_state(musb, OTG_STATE_A_IDLE); MUSB_HST_MODE(musb); break; case OTG_STATE_A_PERIPHERAL: - musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON; + musb_set_state(musb, OTG_STATE_A_WAIT_BCON); MUSB_HST_MODE(musb); break; case OTG_STATE_B_WAIT_ACON: case OTG_STATE_B_HOST: case OTG_STATE_B_PERIPHERAL: case OTG_STATE_B_IDLE: - musb->xceiv->otg->state = OTG_STATE_B_IDLE; + musb_set_state(musb, OTG_STATE_B_IDLE); + usb_gadget_set_state(&musb->g, USB_STATE_NOTATTACHED); break; case OTG_STATE_B_SRP_INIT: break; @@ -2079,13 +2080,13 @@ __acquires(musb->lock) * In that case, do not rely on devctl for setting * peripheral mode. */ - musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; + musb_set_state(musb, OTG_STATE_B_PERIPHERAL); musb->g.is_a_peripheral = 0; } else if (devctl & MUSB_DEVCTL_BDEVICE) { - musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; + musb_set_state(musb, OTG_STATE_B_PERIPHERAL); musb->g.is_a_peripheral = 0; } else { - musb->xceiv->otg->state = OTG_STATE_A_PERIPHERAL; + musb_set_state(musb, OTG_STATE_A_PERIPHERAL); musb->g.is_a_peripheral = 1; } |
