USB: dwc3-msm: Add sysfs entry to manually set speed

In some cases it is useful to manually force the controller to
run at certain speeds (USB 2.0 or USB 3.0 speeds). For example,
EUD (Emebedded USB Debug) can only work when controller is
operating in USB 2.0 speeds.  User can force USB 2.0 if EUD is
required.

Change-Id: Id022f372014a9218537bd1b5477d4555aff4578c
Signed-off-by: Vamsi Krishna Samavedam <vskrishn@codeaurora.org>
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 77824d4..079e6b1a 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -2722,6 +2722,38 @@
 
 static DEVICE_ATTR_RW(mode);
 
+static ssize_t speed_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct dwc3_msm *mdwc = dev_get_drvdata(dev);
+	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
+
+	return snprintf(buf, PAGE_SIZE, "%s\n",
+			usb_speed_string(dwc->max_hw_supp_speed));
+}
+
+static ssize_t speed_store(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct dwc3_msm *mdwc = dev_get_drvdata(dev);
+	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
+	enum usb_device_speed req_speed = USB_SPEED_UNKNOWN;
+
+	if (sysfs_streq(buf, "high"))
+		req_speed = USB_SPEED_HIGH;
+	else if (sysfs_streq(buf, "super"))
+		req_speed = USB_SPEED_SUPER;
+
+	if (req_speed != USB_SPEED_UNKNOWN &&
+			req_speed != dwc->max_hw_supp_speed) {
+		dwc->maximum_speed = dwc->max_hw_supp_speed = req_speed;
+		schedule_work(&mdwc->restart_usb_work);
+	}
+
+	return count;
+}
+static DEVICE_ATTR_RW(speed);
+
 static int dwc3_msm_probe(struct platform_device *pdev)
 {
 	struct device_node *node = pdev->dev.of_node, *dwc3_node;
@@ -3043,6 +3075,7 @@
 		dwc3_msm_id_notifier(&mdwc->id_nb, true, mdwc->extcon_id);
 
 	device_create_file(&pdev->dev, &dev_attr_mode);
+	device_create_file(&pdev->dev, &dev_attr_speed);
 
 	schedule_delayed_work(&mdwc->sm_work, 0);