usb: renesas_usbhs: modify device attach method

Current renesas_usbhs had been assigning udev to each urb.
It was executed even though it was device0.
For this reason, the device0 had to set the new device address
which has still not been assigned. (it will be assigned on next step).
Current renesas_usbhs used fixed address for it.
but it is not good for USB hub support.
This patch modifies this issue.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c
index 0dbbc661..164f28e 100644
--- a/drivers/usb/renesas_usbhs/mod_host.c
+++ b/drivers/usb/renesas_usbhs/mod_host.c
@@ -220,10 +220,30 @@
 	return !list_empty(&udev->ep_list_head);
 }
 
+static struct usbhsh_device *usbhsh_device_get(struct usbhsh_hpriv *hpriv,
+					       struct urb *urb)
+{
+	struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
+	struct usbhsh_device *udev = usbhsh_usbv_to_udev(usbv);
+
+	/* usbhsh_device_attach() is still not called */
+	if (!udev)
+		return NULL;
+
+	/* if it is device0, return it */
+	if (0 == usb_pipedevice(urb->pipe))
+		return usbhsh_device0(hpriv);
+
+	/* return attached device */
+	return udev;
+}
+
 static struct usbhsh_device *usbhsh_device_attach(struct usbhsh_hpriv *hpriv,
 						 struct urb *urb)
 {
 	struct usbhsh_device *udev = NULL;
+	struct usbhsh_device *udev0 = usbhsh_device0(hpriv);
+	struct usbhsh_device *pos;
 	struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
 	struct device *dev = usbhsh_hcd_to_dev(hcd);
 	struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
@@ -232,31 +252,29 @@
 	u16 upphub, hubport;
 	int i;
 
+	/*
+	 * This function should be called only while urb is pointing to device0.
+	 * It will attach unused usbhsh_device to urb (usbv),
+	 * and initialize device0.
+	 * You can use usbhsh_device_get() to get "current" udev,
+	 * and usbhsh_usbv_to_udev() is for "attached" udev.
+	 */
+	if (0 != usb_pipedevice(urb->pipe)) {
+		dev_err(dev, "%s fail: urb isn't pointing device0\n", __func__);
+		return NULL;
+	}
+
 	/********************  spin lock ********************/
 	usbhs_lock(priv, flags);
 
 	/*
-	 * find device
+	 * find unused device
 	 */
-	if (0 == usb_pipedevice(urb->pipe)) {
-		/*
-		 * device0 is special case
-		 */
-		udev = usbhsh_device0(hpriv);
-		if (usbhsh_udev_is_used(udev))
-			udev = NULL;
-	} else {
-		struct usbhsh_device *pos;
-
-		/*
-		 * find unused device
-		 */
-		usbhsh_for_each_udev(pos, hpriv, i) {
-			if (usbhsh_udev_is_used(pos))
-				continue;
-			udev = pos;
-			break;
-		}
+	usbhsh_for_each_udev(pos, hpriv, i) {
+		if (usbhsh_udev_is_used(pos))
+			continue;
+		udev = pos;
+		break;
 	}
 
 	if (udev) {
@@ -280,9 +298,22 @@
 	if (usbhsh_device_has_endpoint(udev))
 		dev_warn(dev, "udev have old endpoint\n");
 
+	if (usbhsh_device_has_endpoint(udev0))
+		dev_warn(dev, "udev0 have old endpoint\n");
+
 	/* uep will be attached */
+	INIT_LIST_HEAD(&udev0->ep_list_head);
 	INIT_LIST_HEAD(&udev->ep_list_head);
 
+	/*
+	 * set device0 config
+	 */
+	usbhs_set_device_config(priv,
+				0, 0, 0, usbv->speed);
+
+	/*
+	 * set new device config
+	 */
 	upphub	= 0;
 	hubport	= 0;
 	if (!usbhsh_connected_to_rhdev(hcd, udev)) {
@@ -296,7 +327,6 @@
 			upphub, hubport, parent);
 	}
 
-	/* set device config */
 	usbhs_set_device_config(priv,
 			       usbhsh_device_number(hpriv, udev),
 			       upphub, hubport, usbv->speed);
@@ -322,6 +352,15 @@
 	if (usbhsh_device_has_endpoint(udev))
 		dev_warn(dev, "udev still have endpoint\n");
 
+	/*
+	 * There is nothing to do if it is device0.
+	 * see
+	 *  usbhsh_device_attach()
+	 *  usbhsh_device_get()
+	 */
+	if (0 == usbhsh_device_number(hpriv, udev))
+		return;
+
 	/********************  spin lock ********************/
 	usbhs_lock(priv, flags);
 
@@ -345,8 +384,7 @@
 				  gfp_t mem_flags)
 {
 	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
-	struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
-	struct usbhsh_device *udev = usbhsh_usbv_to_udev(usbv);
+	struct usbhsh_device *udev = usbhsh_device_get(hpriv, urb);
 	struct usb_host_endpoint *ep = urb->ep;
 	struct usbhsh_ep *uep;
 	struct usbhsh_pipe_info *info;
@@ -577,11 +615,15 @@
 	/*
 	 * renesas_usbhs can not use original usb address.
 	 * see HARDWARE LIMITATION.
-	 * modify usb address here.
+	 * modify usb address here to use attached device.
+	 * see usbhsh_device_attach()
 	 */
 	if (usbhsh_is_request_address(urb)) {
-		/* FIXME */
-		req.wValue = 1;
+		struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
+		struct usbhsh_device *udev = usbhsh_usbv_to_udev(usbv);
+
+		/* udev is a attached device */
+		req.wValue = usbhsh_device_number(hpriv, udev);
 		dev_dbg(dev, "create new address - %d\n", req.wValue);
 	}
 
@@ -742,7 +784,6 @@
 	struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd);
 	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
 	struct device *dev = usbhs_priv_to_dev(priv);
-	struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
 	struct usb_host_endpoint *ep = urb->ep;
 	struct usbhsh_device *new_udev = NULL;
 	int is_dir_in = usb_pipein(urb->pipe);
@@ -758,7 +799,7 @@
 	/*
 	 * attach udev if needed
 	 */
-	if (!usbhsh_usbv_to_udev(usbv)) {
+	if (!usbhsh_device_get(hpriv, urb)) {
 		new_udev = usbhsh_device_attach(hpriv, urb);
 		if (!new_udev) {
 			ret = -EIO;