summaryrefslogtreecommitdiff
path: root/drivers/usb/dwc3/dwc3-msm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/dwc3/dwc3-msm.c')
-rw-r--r--drivers/usb/dwc3/dwc3-msm.c48
1 files changed, 46 insertions, 2 deletions
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index b6b25c75b80c..c40c15a22abc 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -278,6 +278,7 @@ struct dwc3_msm {
enum usb_device_speed override_usb_speed;
bool core_init_failed;
+ bool usb_data_enabled;
};
#define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */
@@ -2692,6 +2693,9 @@ static int dwc3_msm_id_notifier(struct notifier_block *nb,
goto done;
}
+ 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);
@@ -2769,6 +2773,14 @@ static int dwc3_msm_vbus_notifier(struct notifier_block *nb,
goto done;
}
+ if (!mdwc->usb_data_enabled) {
+ if (event)
+ dwc3_msm_gadget_vbus_draw(mdwc, 500);
+ else
+ dwc3_msm_gadget_vbus_draw(mdwc, 0);
+ return NOTIFY_DONE;
+ }
+
dev_dbg(mdwc->dev, "vbus:%ld event received\n", event);
if (mdwc->vbus_active == event)
@@ -2977,7 +2989,6 @@ static ssize_t xhci_link_compliance_store(struct device *dev,
return ret;
}
-
static DEVICE_ATTR_RW(xhci_link_compliance);
static ssize_t usb_compliance_mode_show(struct device *dev,
@@ -3004,6 +3015,33 @@ static ssize_t usb_compliance_mode_store(struct device *dev,
}
static DEVICE_ATTR_RW(usb_compliance_mode);
+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)
{
struct device_node *node = pdev->dev.of_node, *dwc3_node;
@@ -3336,6 +3374,9 @@ static int dwc3_msm_probe(struct platform_device *pdev)
mdwc->pm_qos_latency = 0;
}
+ /* set the initial value */
+ mdwc->usb_data_enabled = true;
+
mdwc->usb_psy = power_supply_get_by_name("usb");
if (!mdwc->usb_psy) {
dev_warn(mdwc->dev, "Could not get usb power_supply\n");
@@ -3365,6 +3406,7 @@ static int dwc3_msm_probe(struct platform_device *pdev)
device_create_file(&pdev->dev, &dev_attr_speed);
device_create_file(&pdev->dev, &dev_attr_xhci_link_compliance);
device_create_file(&pdev->dev, &dev_attr_usb_compliance_mode);
+ device_create_file(&pdev->dev, &dev_attr_usb_data_enabled);
host_mode = usb_get_dr_mode(&mdwc->dwc3->dev) == USB_DR_MODE_HOST;
if (host_mode ||
@@ -3400,6 +3442,7 @@ static int dwc3_msm_remove(struct platform_device *pdev)
device_remove_file(&pdev->dev, &dev_attr_mode);
device_remove_file(&pdev->dev, &dev_attr_xhci_link_compliance);
+ device_create_file(&pdev->dev, &dev_attr_usb_data_enabled);
if (cpu_to_affin)
unregister_cpu_notifier(&mdwc->dwc3_cpu_notifier);
@@ -4009,7 +4052,8 @@ static void dwc3_otg_sm_work(struct work_struct *w)
work = 1;
break;
} else {
- dwc3_msm_gadget_vbus_draw(mdwc, 0);
+ if (mdwc->usb_data_enabled)
+ dwc3_msm_gadget_vbus_draw(mdwc, 0);
pm_relax(mdwc->dev);
dev_dbg(mdwc->dev, "Cable disconnected\n");
}