usb: new attributes implementation to enable/disable usb data
Bug: 184613044
Test: driver probe and attributes access normally
Signed-off-by: Albert Wang <albertccwang@google.com>
Change-Id: Ia34cfd8e76a21f7239e356608e46ddeebd6fa10a
diff --git a/Documentation/ABI/testing/sysfs-class-udc b/Documentation/ABI/testing/sysfs-class-udc
new file mode 100644
index 0000000..1b9c566
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-udc
@@ -0,0 +1,16 @@
+What: /sys/class/udc/<udc name>/device/usb_data_enabled
+Date: December 2020
+Contact: "Ray Chi" <raychi@google.com>
+Description:
+ The attribute can allow user space can check and modify
+ the value to enable or disable usb functionality. Therefore,
+ if the attritube is set to 0, USB host and USB peripheral
+ modes wouldn't be working.
+
+ Example:
+ Enable USB data functionality
+ # echo 1 > /sys/class/udc/.../device/usb_data_enabled
+
+ Disable USB data functionality
+ # echo 0 > /sys/class/udc/.../device/usb_data_enabled
+
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 872df4f..e1c17e2f 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -304,6 +304,7 @@
enum usb_device_speed override_usb_speed;
u32 auto_vbus_src_sel_threshold;
+ bool usb_data_enabled;
};
#define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */
@@ -2987,6 +2988,9 @@
struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
enum dwc3_id_state id;
+ if (!mdwc->usb_data_enabled)
+ return NOTIFY_DONE;
+
id = event ? DWC3_ID_GROUND : DWC3_ID_FLOAT;
dev_dbg(mdwc->dev, "host:%ld (id:%d) event received\n", event, id);
@@ -3032,6 +3036,9 @@
struct dwc3_msm *mdwc = container_of(nb, struct dwc3_msm, vbus_nb);
struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
+ if (!mdwc->usb_data_enabled)
+ return NOTIFY_DONE;
+
dev_dbg(mdwc->dev, "vbus:%ld event received\n", event);
if (mdwc->vbus_active == event)
@@ -3388,11 +3395,34 @@
return ret;
}
-
static DEVICE_ATTR_RW(xhci_link_compliance);
+static ssize_t usb_data_enabled_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dwc3_msm *mdwc = dev_get_drvdata(dev);
+ return sysfs_emit(buf, "%s\n",
+ mdwc->usb_data_enabled ? "enabled" : "disabled");
+}
+static ssize_t usb_data_enabled_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct dwc3_msm *mdwc = dev_get_drvdata(dev);
+
+ if (kstrtobool(buf, &mdwc->usb_data_enabled))
+ return -EINVAL;
+
+ if (!mdwc->usb_data_enabled) {
+ mdwc->vbus_active = false;
+ mdwc->id_state = DWC3_ID_FLOAT;
+ dwc3_ext_event_notify(mdwc);
+ }
+
+ return count;
+}
+static DEVICE_ATTR_RW(usb_data_enabled);
static int dwc3_msm_probe(struct platform_device *pdev)
{
@@ -3756,11 +3786,14 @@
dev_info(mdwc->dev, "charger detection in progress\n");
}
+ /* set the initial value */
+ mdwc->usb_data_enabled = true;
device_create_file(&pdev->dev, &dev_attr_mode);
device_create_file(&pdev->dev, &dev_attr_speed);
device_create_file(&pdev->dev, &dev_attr_usb_compliance_mode);
device_create_file(&pdev->dev, &dev_attr_auto_vbus_src_sel_threshold);
device_create_file(&pdev->dev, &dev_attr_xhci_link_compliance);
+ device_create_file(&pdev->dev, &dev_attr_usb_data_enabled);
host_mode = usb_get_dr_mode(&mdwc->dwc3->dev) == USB_DR_MODE_HOST;
if (!dwc->is_drd && host_mode) {
@@ -3803,6 +3836,8 @@
device_remove_file(&pdev->dev, &dev_attr_usb_compliance_mode);
device_remove_file(&pdev->dev, &dev_attr_auto_vbus_src_sel_threshold);
device_remove_file(&pdev->dev, &dev_attr_xhci_link_compliance);
+ device_create_file(&pdev->dev, &dev_attr_usb_data_enabled);
+
if (mdwc->usb_psy)
power_supply_put(mdwc->usb_psy);