[ONE Android Development] Nbhs:
Hi sollapse, thank you a lot for this patch, i modified it a little for my xperia z2, it seems to be working just fine, it detects when power is disconnected and switches back to OTG_STATE_A_IDLE automatically, anyway, the only thing that i couldnt get to work is once it is on host mode, when i connect the power it doesnt start charging, perhaps you can find a way to get it working, here's my patch:

--- dwc3_otg.c	2015-09-22 14:44:45.115324661 -0300
+++ dwc3_otg.c.new	2015-09-22 14:47:40.950239287 -0300
@@ -45,6 +45,12 @@ static void dwc3_otg_reset(struct dwc3_o
static void dwc3_otg_notify_host_mode(struct usb_otg *otg, int host_mode);
static void dwc3_otg_reset(struct dwc3_otg *dotg);

+/*OTG charging hack*/
+static bool aca_enable = 0;
+static bool enable_otg_charge = 0;
+module_param(enable_otg_charge, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(enable_otg_charge, "Force ACA host mode to allow charging and host.");
+
/**
* dwc3_otg_set_host_regs - reset dwc3 otg registers to host operation.
*
@@ -204,41 +210,45 @@ static int dwc3_otg_start_host(struct us

if (!dwc->xhci)
return -EINVAL;
-
-	if (!dotg->vbus_otg) {
-	dotg->vbus_otg = devm_regulator_get(dwc->dev->parent,
-	"vbus_dwc3");
-	if (IS_ERR(dotg->vbus_otg)) {
-	dev_err(dwc->dev, "Failed to get vbus regulator\n");
-	ret = PTR_ERR(dotg->vbus_otg);
-	dotg->vbus_otg = 0;
-	return ret;
-	}
-	}
-
+
+ if(!aca_enable){
+ if (!dotg->vbus_otg) {
+ dotg->vbus_otg = devm_regulator_get(dwc->dev->parent,
+ "vbus_dwc3");
+ if (IS_ERR(dotg->vbus_otg)) {
+ dev_err(dwc->dev, "Failed to get vbus regulator\n");
+ ret = PTR_ERR(dotg->vbus_otg);
+ dotg->vbus_otg = 0;
+ return ret;
+ }
+ }
+ }
+
if (on) {
dev_dbg(otg->phy->dev, "%s: turn on host\n", __func__);

dwc3_otg_notify_host_mode(otg, on);
-
-	/* register ocp notification */
-	if (ext_xceiv && ext_xceiv->otg_capability &&
-	ext_xceiv->ext_ocp_notification.notify) {
-	ret = regulator_register_ocp_notification(
-	dotg->vbus_otg,
-	&ext_xceiv->ext_ocp_notification);
-	if (ret)
-	dev_err(otg->phy->dev,
-	"unable to register ocp\n");
-	}
-
-	ret = regulator_enable(dotg->vbus_otg);
-	if (ret) {
-	dev_err(otg->phy->dev, "unable to enable vbus_otg\n");
-	dwc3_otg_notify_host_mode(otg, 0);
-	return ret;
-	}
-
+
+ if(!aca_enable){
+ /* register ocp notification */
+ if (ext_xceiv && ext_xceiv->otg_capability &&
+ ext_xceiv->ext_ocp_notification.notify) {
+ ret = regulator_register_ocp_notification(
+ dotg->vbus_otg,
+ &ext_xceiv->ext_ocp_notification);
+ if (ret)
+ dev_err(otg->phy->dev,
+ "unable to register ocp\n");
+ }
+
+ ret = regulator_enable(dotg->vbus_otg);
+ if (ret) {
+ dev_err(otg->phy->dev, "unable to enable vbus_otg\n");
+ dwc3_otg_notify_host_mode(otg, 0);
+ return ret;
+ }
+ }
+
/* The delay between enabling regulator and adding the
platform device is needed to succeed in the enumeration
for certain devices. */
@@ -269,7 +279,9 @@ static int dwc3_otg_start_host(struct us
dev_err(otg->phy->dev,
"%s: failed to add XHCI pdev ret=%d\n",
__func__, ret);
-	regulator_disable(dotg->vbus_otg);
+ if(!aca_enable)
+ regulator_disable(dotg->vbus_otg);
+
dwc3_otg_notify_host_mode(otg, 0);
return ret;
}
@@ -279,24 +291,27 @@ static int dwc3_otg_start_host(struct us
dwc3_otg_reset(dotg);
} else {
dev_dbg(otg->phy->dev, "%s: turn off host\n", __func__);
-
-	ret = regulator_disable(dotg->vbus_otg);
-	if (ret) {
-	dev_err(otg->phy->dev, "unable to disable vbus_otg\n");
-	return ret;
-	}
-
-	/* unregister ocp notification */
-	if (ext_xceiv && ext_xceiv->otg_capability &&
-	ext_xceiv->ext_ocp_notification.notify) {
-	ret = regulator_register_ocp_notification(
-	dotg->vbus_otg, NULL);
-	if (ret)
-	dev_err(otg->phy->dev,
-	"unable to unregister ocp\n");
-	}
-
-	dwc3_otg_notify_host_mode(otg, on);
+
+ if(!aca_enable){
+ ret = regulator_disable(dotg->vbus_otg);
+ if (ret) {
+ dev_err(otg->phy->dev, "unable to disable vbus_otg\n");
+ return ret;
+ }
+
+ /* unregister ocp notification */
+ if (ext_xceiv && ext_xceiv->otg_capability &&
+ ext_xceiv->ext_ocp_notification.notify) {
+ ret = regulator_register_ocp_notification(
+ dotg->vbus_otg, NULL);
+ if (ret)
+ dev_err(otg->phy->dev,
+ "unable to unregister ocp\n");
+ }
+ }
+
+ if(!aca_enable)
+ dwc3_otg_notify_host_mode(otg, on);

platform_device_del(dwc->xhci);
/*
@@ -341,8 +356,11 @@ static int dwc3_otg_set_host(struct usb_
* required for XHCI controller before setting OTG Port Power
* TODO: Tune this delay
*/
-	msleep(300);
-	dwc3_otg_set_host_power(dotg);
+
+ msleep(300);
+ if(!aca_enable){
+ dwc3_otg_set_host_power(dotg);
+ }
} else {
otg->host = NULL;
}
@@ -972,7 +990,17 @@ static void dwc3_otg_sm_work(struct work
dev_dbg(phy->dev, "vbus_drop_det\n");
/* staying on here until exit from A-Device */
} else {
-	phy->state = OTG_STATE_A_HOST;
+ //if we have power and enable_otg_charge, force charging on
+ if (test_bit(B_SESS_VLD, &dotg->inputs) && enable_otg_charge){
+ if(charger){
+ dev_info(phy->dev, "OTG charging is ON!!!\n");
+ aca_enable = 1;
+ charger->chg_type =DWC3_SDP_CHARGER;
+ dwc3_otg_set_power(phy, DWC3_IDEV_CHG_MAX);
+ }
+ } else
+ aca_enable = 0;
+ phy->state = OTG_STATE_A_HOST;
ret = dwc3_otg_start_host(&dotg->otg, 1);
if ((ret == -EPROBE_DEFER) &&
dotg->vbus_retry_count < 3) {
@@ -1000,7 +1028,15 @@ static void dwc3_otg_sm_work(struct work
break;

case OTG_STATE_A_HOST:
-	if (test_bit(ID, &dotg->inputs)) {
+ if (enable_otg_charge){
+ //detect power change and switch back to OTG_STATE_A_IDLE
+ if(!test_bit(B_SESS_VLD, &dotg->inputs)){
+ dev_info(phy->dev, "Power disconnected, charging disabled!!!\n");
+	dwc3_otg_start_host(&dotg->otg, 0);
+	phy->state = OTG_STATE_A_IDLE;
+	work = 1;
+ }
+ } else if (test_bit(ID, &dotg->inputs)) {
dev_dbg(phy->dev, "id\n");
dwc3_otg_start_host(&dotg->otg, 0);
phy->state = OTG_STATE_B_IDLE;