diff options
Diffstat (limited to 'drivers/usb/gadget/fsl_usb2_udc.c')
-rw-r--r-- | drivers/usb/gadget/fsl_usb2_udc.c | 176 |
1 files changed, 77 insertions, 99 deletions
diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c index 3ca2b3159f00..d57bcfbc08a5 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.c +++ b/drivers/usb/gadget/fsl_usb2_udc.c @@ -228,7 +228,7 @@ static int dr_controller_setup(struct fsl_udc *udc) /* Config PHY interface */ portctrl = fsl_readl(&dr_regs->portsc1); - portctrl &= ~(PORTSCX_PHY_TYPE_SEL & PORTSCX_PORT_WIDTH); + portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH); switch (udc->phy_mode) { case FSL_USB2_PHY_ULPI: portctrl |= PORTSCX_PTS_ULPI; @@ -601,39 +601,6 @@ static void fsl_free_request(struct usb_ep *_ep, struct usb_request *_req) kfree(req); } -/*------------------------------------------------------------------ - * Allocate an I/O buffer -*---------------------------------------------------------------------*/ -static void *fsl_alloc_buffer(struct usb_ep *_ep, unsigned bytes, - dma_addr_t *dma, gfp_t gfp_flags) -{ - struct fsl_ep *ep; - - if (!_ep) - return NULL; - - ep = container_of(_ep, struct fsl_ep, ep); - - return dma_alloc_coherent(ep->udc->gadget.dev.parent, - bytes, dma, gfp_flags); -} - -/*------------------------------------------------------------------ - * frees an i/o buffer -*---------------------------------------------------------------------*/ -static void fsl_free_buffer(struct usb_ep *_ep, void *buf, - dma_addr_t dma, unsigned bytes) -{ - struct fsl_ep *ep; - - if (!_ep) - return; - - ep = container_of(_ep, struct fsl_ep, ep); - - dma_free_coherent(ep->udc->gadget.dev.parent, bytes, buf, dma); -} - /*-------------------------------------------------------------------------*/ static int fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req) { @@ -1047,9 +1014,6 @@ static struct usb_ep_ops fsl_ep_ops = { .alloc_request = fsl_alloc_request, .free_request = fsl_free_request, - .alloc_buffer = fsl_alloc_buffer, - .free_buffer = fsl_free_buffer, - .queue = fsl_ep_queue, .dequeue = fsl_ep_dequeue, @@ -1313,31 +1277,32 @@ static void setup_received_irq(struct fsl_udc *udc, udc_reset_ep_queue(udc, 0); + /* We process some stardard setup requests here */ switch (setup->bRequest) { - /* Request that need Data+Status phase from udc */ case USB_REQ_GET_STATUS: - if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_STANDARD)) + /* Data+Status phase from udc */ + if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK)) != (USB_DIR_IN | USB_TYPE_STANDARD)) break; ch9getstatus(udc, setup->bRequestType, wValue, wIndex, wLength); - break; + return; - /* Requests that need Status phase from udc */ case USB_REQ_SET_ADDRESS: + /* Status phase from udc */ if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE)) break; ch9setaddress(udc, wValue, wIndex, wLength); - break; + return; - /* Handled by udc, no data, status by udc */ case USB_REQ_CLEAR_FEATURE: case USB_REQ_SET_FEATURE: - { /* status transaction */ + /* Status phase from udc */ + { int rc = -EOPNOTSUPP; - if ((setup->bRequestType & USB_RECIP_MASK) - == USB_RECIP_ENDPOINT) { + if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) + == (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) { int pipe = get_pipe_by_windex(wIndex); struct fsl_ep *ep; @@ -1351,8 +1316,9 @@ static void setup_received_irq(struct fsl_udc *udc, ? 1 : 0); spin_lock(&udc->lock); - } else if ((setup->bRequestType & USB_RECIP_MASK) - == USB_RECIP_DEVICE) { + } else if ((setup->bRequestType & (USB_RECIP_MASK + | USB_TYPE_MASK)) == (USB_RECIP_DEVICE + | USB_TYPE_STANDARD)) { /* Note: The driver has not include OTG support yet. * This will be set when OTG support is added */ if (!udc->gadget.is_otg) @@ -1365,39 +1331,42 @@ static void setup_received_irq(struct fsl_udc *udc, USB_DEVICE_A_ALT_HNP_SUPPORT) udc->gadget.a_alt_hnp_support = 1; rc = 0; - } + } else + break; + if (rc == 0) { if (ep0_prime_status(udc, EP_DIR_IN)) ep0stall(udc); } - break; + return; } - /* Requests handled by gadget */ - default: - if (wLength) { - /* Data phase from gadget, status phase from udc */ - udc->ep0_dir = (setup->bRequestType & USB_DIR_IN) - ? USB_DIR_IN : USB_DIR_OUT; - spin_unlock(&udc->lock); - if (udc->driver->setup(&udc->gadget, - &udc->local_setup_buff) < 0) - ep0stall(udc); - spin_lock(&udc->lock); - udc->ep0_state = (setup->bRequestType & USB_DIR_IN) - ? DATA_STATE_XMIT : DATA_STATE_RECV; - } else { - /* No data phase, IN status from gadget */ - udc->ep0_dir = USB_DIR_IN; - spin_unlock(&udc->lock); - if (udc->driver->setup(&udc->gadget, - &udc->local_setup_buff) < 0) - ep0stall(udc); - spin_lock(&udc->lock); - udc->ep0_state = WAIT_FOR_OUT_STATUS; - } + default: break; } + + /* Requests handled by gadget */ + if (wLength) { + /* Data phase from gadget, status phase from udc */ + udc->ep0_dir = (setup->bRequestType & USB_DIR_IN) + ? USB_DIR_IN : USB_DIR_OUT; + spin_unlock(&udc->lock); + if (udc->driver->setup(&udc->gadget, + &udc->local_setup_buff) < 0) + ep0stall(udc); + spin_lock(&udc->lock); + udc->ep0_state = (setup->bRequestType & USB_DIR_IN) + ? DATA_STATE_XMIT : DATA_STATE_RECV; + } else { + /* No data phase, IN status from gadget */ + udc->ep0_dir = USB_DIR_IN; + spin_unlock(&udc->lock); + if (udc->driver->setup(&udc->gadget, + &udc->local_setup_buff) < 0) + ep0stall(udc); + spin_lock(&udc->lock); + udc->ep0_state = WAIT_FOR_OUT_STATUS; + } } /* Process request for Data or Status phase of ep0 @@ -2189,27 +2158,19 @@ static void fsl_udc_release(struct device *dev) * init resource for globle controller * Return the udc handle on success or NULL on failure ------------------------------------------------------------------*/ -static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev) +static int __init struct_udc_setup(struct fsl_udc *udc, + struct platform_device *pdev) { - struct fsl_udc *udc; struct fsl_usb2_platform_data *pdata; size_t size; - udc = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL); - if (udc == NULL) { - ERR("malloc udc failed\n"); - return NULL; - } - pdata = pdev->dev.platform_data; udc->phy_mode = pdata->phy_mode; - /* max_ep_nr is bidirectional ep number, max_ep doubles the number */ - udc->max_ep = pdata->max_ep_nr * 2; udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL); if (!udc->eps) { ERR("malloc fsl_ep failed\n"); - goto cleanup; + return -1; } /* initialized QHs, take care of alignment */ @@ -2225,7 +2186,7 @@ static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev) if (!udc->ep_qh) { ERR("malloc QHs for udc failed\n"); kfree(udc->eps); - goto cleanup; + return -1; } udc->ep_qh_size = size; @@ -2244,11 +2205,7 @@ static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev) udc->remote_wakeup = 0; /* default to 0 on reset */ spin_lock_init(&udc->lock); - return udc; - -cleanup: - kfree(udc); - return NULL; + return 0; } /*---------------------------------------------------------------- @@ -2287,35 +2244,37 @@ static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index, } /* Driver probe function - * all intialize operations implemented here except enabling usb_intr reg + * all intialization operations implemented here except enabling usb_intr reg + * board setup should have been done in the platform code */ static int __init fsl_udc_probe(struct platform_device *pdev) { struct resource *res; int ret = -ENODEV; unsigned int i; + u32 dccparams; if (strcmp(pdev->name, driver_name)) { VDBG("Wrong device\n"); return -ENODEV; } - /* board setup should have been done in the platform code */ - - /* Initialize the udc structure including QH member and other member */ - udc_controller = struct_udc_setup(pdev); - if (!udc_controller) { - VDBG("udc_controller is NULL \n"); + udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL); + if (udc_controller == NULL) { + ERR("malloc udc failed\n"); return -ENOMEM; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) + if (!res) { + kfree(udc_controller); return -ENXIO; + } if (!request_mem_region(res->start, res->end - res->start + 1, driver_name)) { ERR("request mem region for %s failed \n", pdev->name); + kfree(udc_controller); return -EBUSY; } @@ -2328,13 +2287,24 @@ static int __init fsl_udc_probe(struct platform_device *pdev) usb_sys_regs = (struct usb_sys_interface *) ((u32)dr_regs + USB_DR_SYS_OFFSET); + /* Read Device Controller Capability Parameters register */ + dccparams = fsl_readl(&dr_regs->dccparams); + if (!(dccparams & DCCPARAMS_DC)) { + ERR("This SOC doesn't support device role\n"); + ret = -ENODEV; + goto err2; + } + /* Get max device endpoints */ + /* DEN is bidirectional ep number, max_ep doubles the number */ + udc_controller->max_ep = (dccparams & DCCPARAMS_DEN_MASK) * 2; + udc_controller->irq = platform_get_irq(pdev, 0); if (!udc_controller->irq) { ret = -ENODEV; goto err2; } - ret = request_irq(udc_controller->irq, fsl_udc_irq, SA_SHIRQ, + ret = request_irq(udc_controller->irq, fsl_udc_irq, IRQF_SHARED, driver_name, udc_controller); if (ret != 0) { ERR("cannot request irq %d err %d \n", @@ -2342,6 +2312,13 @@ static int __init fsl_udc_probe(struct platform_device *pdev) goto err2; } + /* Initialize the udc structure including QH member and other member */ + if (struct_udc_setup(udc_controller, pdev)) { + ERR("Can't initialize udc data structure\n"); + ret = -ENOMEM; + goto err3; + } + /* initialize usb hw reg except for regs for EP, * leave usbintr reg untouched */ dr_controller_setup(udc_controller); @@ -2403,6 +2380,7 @@ err2: iounmap(dr_regs); err1: release_mem_region(res->start, res->end - res->start + 1); + kfree(udc_controller); return ret; } |