dwc3-msm: Add dynamic detection of USB connector
Register extra extcon phandles which are passed
from DT for microUSB connector based on the power
supply property POWER_SUPPLY_PROP_CONNECTOR_TYPE.
Also, vote for host mode VBUS supply only in case
of microUSB connector or type-C connector with
the "qcom,no-vbus-vote-with-type-C" flag not set
from the DT.
Change-Id: Icf1789c3a1f1aa17137f4c4aed8a83f78ac8d6f3
Signed-off-by: Pratham Pratap <prathampratap@codeaurora.org>
Signed-off-by: Ajay Agarwal <ajaya@codeaurora.org>
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index b6ad39b..874499d 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -245,6 +245,10 @@
struct notifier_block dwc3_cpu_notifier;
struct notifier_block usbdev_nb;
bool hc_died;
+ /* for usb connector either type-C or microAB */
+ bool type_c;
+ /* whether to vote for VBUS reg in host mode */
+ bool no_vbus_vote_type_c;
struct extcon_dev *extcon_vbus;
struct extcon_dev *extcon_id;
@@ -2898,7 +2902,7 @@
return NOTIFY_DONE;
}
-static int dwc3_msm_extcon_register(struct dwc3_msm *mdwc)
+static int dwc3_msm_extcon_register(struct dwc3_msm *mdwc, int start_idx)
{
struct device_node *node = mdwc->dev->of_node;
struct extcon_dev *edev;
@@ -2907,8 +2911,11 @@
if (!of_property_read_bool(node, "extcon"))
return 0;
- /* Use first phandle (mandatory) for USB vbus status notification */
- edev = extcon_get_edev_by_phandle(mdwc->dev, 0);
+ /*
+ * Use mandatory phandle (index 0 for type-C; index 3 for microUSB)
+ * for USB vbus status notification
+ */
+ edev = extcon_get_edev_by_phandle(mdwc->dev, start_idx);
if (IS_ERR(edev) && PTR_ERR(edev) != -ENODEV)
return PTR_ERR(edev);
@@ -2923,9 +2930,12 @@
}
}
- /* Use second phandle (optional) for USB ID status notification */
- if (of_count_phandle_with_args(node, "extcon", NULL) > 1) {
- edev = extcon_get_edev_by_phandle(mdwc->dev, 1);
+ /*
+ * Use optional phandle (index 1 for type-C; index 4 for microUSB)
+ * for USB ID status notification
+ */
+ if (of_count_phandle_with_args(node, "extcon", NULL) > start_idx + 1) {
+ edev = extcon_get_edev_by_phandle(mdwc->dev, start_idx + 1);
if (IS_ERR(edev) && PTR_ERR(edev) != -ENODEV) {
ret = PTR_ERR(edev);
goto err;
@@ -2953,12 +2963,12 @@
}
edev = NULL;
- /* Use third phandle (optional) for EUD based detach/attach events */
+ /* Use optional phandle (index 2) for EUD based detach/attach events */
if (of_count_phandle_with_args(node, "extcon", NULL) > 2) {
edev = extcon_get_edev_by_phandle(mdwc->dev, 2);
if (IS_ERR(edev) && PTR_ERR(edev) != -ENODEV) {
ret = PTR_ERR(edev);
- goto err1;
+ goto err2;
}
}
@@ -3408,10 +3418,6 @@
if (of_property_read_bool(node, "qcom,disable-dev-mode-pm"))
pm_runtime_get_noresume(mdwc->dev);
- ret = dwc3_msm_extcon_register(mdwc);
- if (ret)
- goto put_dwc3;
-
ret = of_property_read_u32(node, "qcom,pm-qos-latency",
&mdwc->pm_qos_latency);
if (ret) {
@@ -3419,15 +3425,34 @@
mdwc->pm_qos_latency = 0;
}
+ mdwc->no_vbus_vote_type_c = of_property_read_bool(node,
+ "qcom,no-vbus-vote-with-type-C");
+
+ /* Mark type-C as true by default */
+ mdwc->type_c = 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");
pval.intval = -EINVAL;
} else {
power_supply_get_property(mdwc->usb_psy,
+ POWER_SUPPLY_PROP_CONNECTOR_TYPE, &pval);
+ if (pval.intval == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+ mdwc->type_c = false;
+ power_supply_get_property(mdwc->usb_psy,
POWER_SUPPLY_PROP_PRESENT, &pval);
}
+ /*
+ * Extcon phandles starting indices in DT:
+ * type-C : 0
+ * microUSB : 3
+ */
+ ret = dwc3_msm_extcon_register(mdwc, mdwc->type_c ? 0 : 3);
+ if (ret)
+ goto put_psy;
+
mutex_init(&mdwc->suspend_resume_mutex);
/* Update initial VBUS/ID state from extcon */
if (mdwc->extcon_vbus && extcon_get_state(mdwc->extcon_vbus,
@@ -3456,6 +3481,12 @@
return 0;
+put_psy:
+ if (mdwc->usb_psy)
+ power_supply_put(mdwc->usb_psy);
+
+ if (cpu_to_affin)
+ unregister_cpu_notifier(&mdwc->dwc3_cpu_notifier);
put_dwc3:
if (mdwc->bus_perf_client)
msm_bus_scale_unregister_client(mdwc->bus_perf_client);
@@ -3478,6 +3509,8 @@
int ret_pm;
device_remove_file(&pdev->dev, &dev_attr_mode);
+ if (mdwc->usb_psy)
+ power_supply_put(mdwc->usb_psy);
if (cpu_to_affin)
unregister_cpu_notifier(&mdwc->dwc3_cpu_notifier);
@@ -3680,7 +3713,8 @@
* IS_ERR: regulator could not be obtained, so skip using it
* Valid pointer otherwise
*/
- if (!mdwc->vbus_reg) {
+ if (!mdwc->vbus_reg && (!mdwc->type_c ||
+ (mdwc->type_c && !mdwc->no_vbus_vote_type_c))) {
mdwc->vbus_reg = devm_regulator_get_optional(mdwc->dev,
"vbus_dwc3");
if (IS_ERR(mdwc->vbus_reg) &&
@@ -3705,7 +3739,7 @@
pm_runtime_get_sync(mdwc->dev);
dbg_event(0xFF, "StrtHost gync",
atomic_read(&mdwc->dev->power.usage_count));
- if (!IS_ERR(mdwc->vbus_reg))
+ if (!IS_ERR_OR_NULL(mdwc->vbus_reg))
ret = regulator_enable(mdwc->vbus_reg);
if (ret) {
dev_err(mdwc->dev, "unable to enable vbus_reg\n");
@@ -3729,7 +3763,7 @@
dev_err(mdwc->dev,
"%s: failed to add XHCI pdev ret=%d\n",
__func__, ret);
- if (!IS_ERR(mdwc->vbus_reg))
+ if (!IS_ERR_OR_NULL(mdwc->vbus_reg))
regulator_disable(mdwc->vbus_reg);
mdwc->hs_phy->flags &= ~PHY_HOST_MODE;
mdwc->ss_phy->flags &= ~PHY_HOST_MODE;
@@ -3770,7 +3804,7 @@
dev_dbg(mdwc->dev, "%s: turn off host\n", __func__);
usb_unregister_atomic_notify(&mdwc->usbdev_nb);
- if (!IS_ERR(mdwc->vbus_reg))
+ if (!IS_ERR_OR_NULL(mdwc->vbus_reg))
ret = regulator_disable(mdwc->vbus_reg);
if (ret) {
dev_err(mdwc->dev, "unable to disable vbus_reg\n");