greybus: es2: implement cport reset control request

Toshiba UniPro IP requires to reset the CPort that has been used in a previous
connection. This commit implement a new control request in order to
reset CPorts on an APBridgeA.

Signed-off-by: Fabien Parent <fparent@baylibre.com>
Reviewed-by: Johan Hovold <johan@hovoldconsulting.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
diff --git a/drivers/staging/greybus/es2.c b/drivers/staging/greybus/es2.c
index 22b67d2..f077038 100644
--- a/drivers/staging/greybus/es2.c
+++ b/drivers/staging/greybus/es2.c
@@ -58,6 +58,9 @@
 /* vendor request to get the number of cports available */
 #define REQUEST_CPORT_COUNT	0x04
 
+/* vendor request to reset a cport state */
+#define REQUEST_RESET_CPORT	0x05
+
 /*
  * @endpoint: bulk in endpoint for CPort data
  * @urb: array of urbs for the CPort in messages
@@ -376,10 +379,44 @@
 	usb_free_urb(urb);
 }
 
+static int cport_reset(struct greybus_host_device *hd, u16 cport_id)
+{
+	struct es1_ap_dev *es1 = hd_to_es1(hd);
+	struct usb_device *udev = es1->usb_dev;
+	int retval;
+
+	retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				 REQUEST_RESET_CPORT,
+				 USB_DIR_OUT | USB_TYPE_VENDOR |
+				 USB_RECIP_INTERFACE, 0, cport_id,
+				 NULL, 0, ES1_TIMEOUT);
+	if (retval < 0) {
+		dev_err(&udev->dev, "failed to reset cport %hu: %d\n", cport_id,
+			retval);
+		return retval;
+	}
+
+	return 0;
+}
+
+static int cport_enable(struct greybus_host_device *hd, u16 cport_id)
+{
+	int retval;
+
+	if (cport_id != GB_SVC_CPORT_ID) {
+		retval = cport_reset(hd, cport_id);
+		if (retval)
+			return retval;
+	}
+
+	return 0;
+}
+
 static struct greybus_host_driver es1_driver = {
 	.hd_priv_size		= sizeof(struct es1_ap_dev),
 	.message_send		= message_send,
 	.message_cancel		= message_cancel,
+	.cport_enable		= cport_enable,
 };
 
 /* Common function to report consistent warnings based on URB status */