USB: fsl_usb2_udc: Get max ep number from DCCPARAMS register

Currently the driver is expecting max ep number in platform
data which isn't passing this information.  This patch fix
the problem by reading it from DCCPARAMS(Device Controller
Capability Parameters) register.  The change also need some
reordering of the probe code.

Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
index 5ea32c3..e4aa29f 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.c
+++ b/drivers/usb/gadget/fsl_usb2_udc.c
@@ -2189,27 +2189,19 @@
  * 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 @@
 	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 @@
 	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 @@
 }
 
 /* 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 @@
 	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 @@
 		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 @@
 	iounmap(dr_regs);
 err1:
 	release_mem_region(res->start, res->end - res->start + 1);
+	kfree(udc_controller);
 	return ret;
 }