]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/usb/gadget/fsl_usb2_udc.c
USB: move <linux/usb_gadget.h> to <linux/usb/gadget.h>
[mirror_ubuntu-artful-kernel.git] / drivers / usb / gadget / fsl_usb2_udc.c
index 157054ea39786936ff3f269bc58bf705ba4d7c83..9bb7f64a85cdb9b0e5041f00162b3f89d0b957dd 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
@@ -228,13 +228,15 @@ static int dr_controller_setup(struct fsl_udc *udc)
 
        /* Config PHY interface */
        portctrl = fsl_readl(&dr_regs->portsc1);
-       portctrl &= ~PORTSCX_PHY_TYPE_SEL;
+       portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
        switch (udc->phy_mode) {
        case FSL_USB2_PHY_ULPI:
                portctrl |= PORTSCX_PTS_ULPI;
                break;
-       case FSL_USB2_PHY_UTMI:
        case FSL_USB2_PHY_UTMI_WIDE:
+               portctrl |= PORTSCX_PTW_16BIT;
+               /* fall through */
+       case FSL_USB2_PHY_UTMI:
                portctrl |= PORTSCX_PTS_UTMI;
                break;
        case FSL_USB2_PHY_SERIAL:
@@ -599,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 NULL;
-
-       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)
 {
@@ -1045,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,
 
@@ -1124,14 +1090,11 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
  */
 static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA)
 {
-#ifdef CONFIG_USB_OTG
        struct fsl_udc *udc;
 
        udc = container_of(gadget, struct fsl_udc, gadget);
-
        if (udc->transceiver)
                return otg_set_power(udc->transceiver, mA);
-#endif
        return -ENOTSUPP;
 }
 
@@ -1154,7 +1117,7 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)
        return 0;
 }
 
-/* defined in usb_gadget.h */
+/* defined in gadget.h */
 static struct usb_gadget_ops fsl_gadget_ops = {
        .get_frame = fsl_get_frame,
        .wakeup = fsl_wakeup,
@@ -1311,31 +1274,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;
 
@@ -1349,11 +1313,12 @@ 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)
+                       if (!gadget_is_otg(udc->gadget))
                                break;
                        else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
                                udc->gadget.b_hnp_enable = 1;
@@ -1362,40 +1327,45 @@ static void setup_received_irq(struct fsl_udc *udc,
                        else if (setup->bRequest ==
                                        USB_DEVICE_A_ALT_HNP_SUPPORT)
                                udc->gadget.a_alt_hnp_support = 1;
+                       else
+                               break;
                        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
@@ -1869,10 +1839,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
        if (!driver || driver != udc_controller->driver || !driver->unbind)
                return -EINVAL;
 
-#ifdef CONFIG_USB_OTG
        if (udc_controller->transceiver)
                (void)otg_set_peripheral(udc_controller->transceiver, 0);
-#endif
 
        /* stop DR, disable intr */
        dr_controller_stop(udc_controller);
@@ -2187,27 +2155,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 */
@@ -2223,7 +2183,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;
@@ -2242,11 +2202,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;
 }
 
 /*----------------------------------------------------------------
@@ -2285,35 +2241,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;
        }
 
@@ -2326,13 +2284,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",
@@ -2340,6 +2309,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);
@@ -2401,6 +2377,7 @@ err2:
        iounmap(dr_regs);
 err1:
        release_mem_region(res->start, res->end - res->start + 1);
+       kfree(udc_controller);
        return ret;
 }