]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/usb/gadget/fsl_usb2_udc.c
USB: fsl_usb2_udc: Get max ep number from DCCPARAMS register
[mv-sheeva.git] / drivers / usb / gadget / fsl_usb2_udc.c
index 5ea32c30878dfa39cd48f76bc8f71ab356ea8c23..e4aa29fc29392f6e4e92dfafdae27c01142429bb 100644 (file)
@@ -2189,27 +2189,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 +2217,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 +2236,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 +2275,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,6 +2318,17 @@ 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;
@@ -2342,6 +2343,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 +2411,7 @@ err2:
        iounmap(dr_regs);
 err1:
        release_mem_region(res->start, res->end - res->start + 1);
+       kfree(udc_controller);
        return ret;
 }