diff options
Diffstat (limited to 'drivers/usb/musb')
-rw-r--r-- | drivers/usb/musb/musb_core.c | 5 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.h | 11 | ||||
-rw-r--r-- | drivers/usb/musb/musb_gadget.c | 9 | ||||
-rw-r--r-- | drivers/usb/musb/musb_host.c | 1 | ||||
-rw-r--r-- | drivers/usb/musb/ux500.c | 66 | ||||
-rw-r--r-- | drivers/usb/musb/ux500_dma.c | 57 |
6 files changed, 129 insertions, 20 deletions
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 67ee65ad637..988bc908fc0 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1041,9 +1041,6 @@ static void musb_shutdown(struct platform_device *pdev) #if defined(CONFIG_USB_MUSB_TUSB6010) || defined(CONFIG_USB_MUSB_OMAP2PLUS) \ || defined(CONFIG_USB_MUSB_AM35X) static ushort __initdata fifo_mode = 4; -#elif defined(CONFIG_USB_MUSB_UX500) \ - || defined(CONFIG_USB_MUSB_UX500_MODULE) -static ushort __initdata fifo_mode = 5; #else static ushort __initdata fifo_mode = 2; #endif @@ -2407,7 +2404,7 @@ static const struct dev_pm_ops musb_dev_pm_ops = { .runtime_resume = musb_runtime_resume, }; -#define MUSB_DEV_PM_OPS (&musb_dev_pm_ops) +#define MUSB_DEV_PM_OPS NULL #else #define MUSB_DEV_PM_OPS NULL #endif diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 0e053b58796..c4cd091a9f5 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -279,6 +279,8 @@ struct musb_platform_ops { int (*adjust_channel_params)(struct dma_channel *channel, u16 packet_sz, u8 *mode, dma_addr_t *dma_addr, u32 *len); + struct usb_ep* (*configure_endpoints)(struct musb *musb, u8 type, + struct usb_endpoint_descriptor *desc); }; /* @@ -665,4 +667,13 @@ static inline int musb_platform_exit(struct musb *musb) return musb->ops->exit(musb); } +static inline struct usb_ep *musb_platform_configure_ep(struct musb *musb, + u8 type, struct usb_endpoint_descriptor *desc) +{ + struct usb_ep *ep = NULL; + + if (musb->ops->configure_endpoints) + ep = musb->ops->configure_endpoints(musb, type, desc); + return ep; +} #endif /* __MUSB_CORE_H__ */ diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index f3fd718554d..ab017cbb78e 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1733,6 +1733,14 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on) return 0; } +static struct usb_ep *musb_gadget_configure_ep(struct usb_gadget *gadget, + u8 type, struct usb_endpoint_descriptor *desc) +{ + struct musb *musb = gadget_to_musb(gadget); + + return musb_platform_configure_ep(musb, type, desc); +} + static const struct usb_gadget_ops musb_gadget_operations = { .get_frame = musb_gadget_get_frame, .wakeup = musb_gadget_wakeup, @@ -1740,6 +1748,7 @@ 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, + .configure_ep = musb_gadget_configure_ep, }; /* ----------------------------------------------------------------------- */ diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 07e25fa1bf2..f12b046b0d6 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -1169,7 +1169,6 @@ void musb_host_tx(struct musb *musb, u8 epnum) } while ((tx_csr & MUSB_TXCSR_TXPKTRDY) != 0); dev_dbg(musb->controller, "TXPKTRDY Cleared. Continue...\n"); - return; } else if (tx_csr & MUSB_TXCSR_H_NAKTIMEOUT) { dev_dbg(musb->controller, "TX end=%d device not responding\n", epnum); diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index bae06ec7d67..ce169460148 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -59,6 +59,7 @@ void ux500_store_context(struct musb *musb) if (is_host_enabled(musb)) { context.frame = musb_readw(musb_base, MUSB_FRAME); context.testmode = musb_readb(musb_base, MUSB_TESTMODE); + context.busctl = musb_read_ulpi_buscontrol(musb->mregs); } context.power = musb_readb(musb_base, MUSB_POWER); context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE); @@ -66,8 +67,19 @@ void ux500_store_context(struct musb *musb) context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE); context.index = musb_readb(musb_base, MUSB_INDEX); context.devctl = DEFAULT_DEVCTL; + for (i = 0; i < musb->config->num_eps; ++i) { - epio = musb->endpoints[i].regs; + struct musb_hw_ep *hw_ep; + + musb_writeb(musb_base, MUSB_INDEX, i); + hw_ep = &musb->endpoints[i]; + if (!hw_ep) + continue; + + epio = hw_ep->regs; + if (!epio) + continue; + context.index_regs[i].txmaxp = musb_readw(epio, MUSB_TXMAXP); context.index_regs[i].txcsr = @@ -132,6 +144,7 @@ void ux500_restore_context(void) if (is_host_enabled(musb)) { musb_writew(musb_base, MUSB_FRAME, context.frame); musb_writeb(musb_base, MUSB_TESTMODE, context.testmode); + musb_write_ulpi_buscontrol(musb->mregs, context.busctl); } musb_writeb(musb_base, MUSB_POWER, context.power); musb_writew(musb_base, MUSB_INTRTXE, context.intrtxe); @@ -140,7 +153,17 @@ void ux500_restore_context(void) musb_writeb(musb_base, MUSB_DEVCTL, context.devctl); for (i = 0; i < musb->config->num_eps; ++i) { - epio = musb->endpoints[i].regs; + struct musb_hw_ep *hw_ep; + + musb_writeb(musb_base, MUSB_INDEX, i); + hw_ep = &musb->endpoints[i]; + if (!hw_ep) + continue; + + epio = hw_ep->regs; + if (!epio) + continue; + musb_writew(epio, MUSB_TXMAXP, context.index_regs[i].txmaxp); musb_writew(epio, MUSB_TXCSR, @@ -205,11 +228,15 @@ static void musb_notify_idle(unsigned long _musb) switch (musb->xceiv->state) { case OTG_STATE_A_WAIT_BCON: - devctl &= ~MUSB_DEVCTL_SESSION; - musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); - musb->xceiv->state = OTG_STATE_B_IDLE; - MUSB_DEV_MODE(musb); + if (devctl & MUSB_DEVCTL_BDEVICE) { + musb->xceiv->state = OTG_STATE_B_IDLE; + MUSB_DEV_MODE(musb); + } else { + musb->xceiv->state = OTG_STATE_A_IDLE; + MUSB_HST_MODE(musb); + } break; + case OTG_STATE_A_SUSPEND: default: break; @@ -239,6 +266,8 @@ static int musb_otg_notifications(struct notifier_block *nb, case USB_EVENT_NONE: dev_dbg(musb->controller, "VBUS Disconnect\n"); + if (is_otg_enabled(musb)) + ux500_musb_set_vbus(musb, 0); break; default: @@ -340,10 +369,34 @@ static void ux500_musb_try_idle(struct musb *musb, unsigned long timeout) (unsigned long)jiffies_to_msecs(timeout - jiffies)); mod_timer(¬ify_timer, timeout); } + static void ux500_musb_enable(struct musb *musb) { ux500_store_context(musb); } + +static struct usb_ep *ux500_musb_configure_endpoints(struct musb *musb, + u8 type, struct usb_endpoint_descriptor *desc) +{ + struct usb_ep *ep = NULL; + struct usb_gadget *gadget = &musb->g; + char name[4]; + + if (USB_ENDPOINT_XFER_INT == type) { + list_for_each_entry(ep, &gadget->ep_list, ep_list) { + if (ep->maxpacket == 512) + continue; + if (NULL == ep->driver_data) { + strncpy(name, (ep->name + 3), 4); + if (USB_DIR_IN & desc->bEndpointAddress) + if (strcmp("in", name) == 0) + return ep; + } + } + } + return ep; +} + static int ux500_musb_init(struct musb *musb) { int status; @@ -389,6 +442,7 @@ static const struct musb_platform_ops ux500_ops = { .try_idle = ux500_musb_try_idle, .enable = ux500_musb_enable, + .configure_endpoints = ux500_musb_configure_endpoints, }; /** diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index d6a606ef839..fc0d3a04859 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -32,6 +32,11 @@ #include <linux/pfn.h> #include <mach/usb.h> #include "musb_core.h" +#undef DBG +#undef WARNING +#undef INFO +#include <linux/usb/composite.h> +#define Ux500_USB_DMA_MIN_TRANSFER_SIZE 512 struct ux500_dma_channel { struct dma_channel channel; @@ -258,13 +263,44 @@ static void ux500_dma_channel_release(struct dma_channel *channel) static int ux500_dma_is_compatible(struct dma_channel *channel, u16 maxpacket, void *buf, u32 length) { - if ((maxpacket & 0x3) || - ((int)buf & 0x3) || - (length < 512) || - (length & 0x3)) - return false; - else - return true; + struct ux500_dma_channel *ux500_channel = channel->private_data; + struct musb_hw_ep *hw_ep = ux500_channel->hw_ep; + struct musb *musb = hw_ep->musb; + struct usb_descriptor_header **descriptors; + struct usb_function *f; + struct usb_gadget *gadget = &musb->g; + struct usb_composite_dev *cdev = get_gadget_data(gadget); + + if (length < Ux500_USB_DMA_MIN_TRANSFER_SIZE) + return 0; + + list_for_each_entry(f, &cdev->config->functions, list) { + if (!strcmp(f->name, "cdc_ethernet") || + !strcmp(f->name, "rndis") || + !strcmp(f->name, "phonet") || + !strcmp(f->name, "adb")) { + if (gadget->speed == USB_SPEED_HIGH) + descriptors = f->hs_descriptors; + else + descriptors = f->descriptors; + + for (; *descriptors; ++descriptors) { + struct usb_endpoint_descriptor *ep; + + if ((*descriptors)->bDescriptorType != + USB_DT_ENDPOINT) + continue; + + ep = (struct usb_endpoint_descriptor *) + *descriptors; + if (ep->bEndpointAddress == + ux500_channel->hw_ep->epnum) + return 0; + } + } + } + + return 1; } /** @@ -282,12 +318,15 @@ static int ux500_dma_channel_program(struct dma_channel *channel, dma_addr_t dma_addr, u32 len) { int ret; + struct ux500_dma_channel *ux500_dma_channel = channel->private_data; BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN || channel->status == MUSB_DMA_STATUS_BUSY); - if (!ux500_dma_is_compatible(channel, packet_sz, (void *)dma_addr, len)) - return false; + if (len < Ux500_USB_DMA_MIN_TRANSFER_SIZE) + return 0; + if (!ux500_dma_channel->is_tx && len < packet_sz) + return 0; channel->status = MUSB_DMA_STATUS_BUSY; channel->actual_len = 0; |