/** * dwc3_otg_start_host - helper function for starting/stoping the host controller driver. * * @otg: Pointer to the otg_transceiver structure. * @on: start / stop the host controller driver. * * Returns 0 on success otherwise negative errno. */ static int dwc3_otg_start_host(struct usb_otg *otg, int on) { struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg); struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv; struct dwc3 *dwc = dotg->dwc; int ret = 0; 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 (on) { dev_dbg(otg->phy->dev, "%s: turn on host\n", __func__); dwc3_otg_notify_host_mode(otg, on); 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; } /* * This should be revisited for more testing post-silicon. * In worst case we may need to disconnect the root hub * before stopping the controller so that it does not * interfere with runtime pm/system pm. * We can also consider registering and unregistering xhci * platform device. It is almost similar to add_hcd and * remove_hcd, But we may not use standard set_host method * anymore. */ dwc3_otg_set_hsphy_auto_suspend(dotg, true); dwc3_otg_set_host_regs(dotg); /* * FIXME If micro A cable is disconnected during system suspend, * xhci platform device will be removed before runtime pm is * enabled for xhci device. Due to this, disable_depth becomes * greater than one and runtimepm is not enabled for next microA * connect. Fix this by calling pm_runtime_init for xhci device. */ pm_runtime_init(&dwc->xhci->dev); ret = platform_device_add(dwc->xhci); if (ret) { dev_err(otg->phy->dev, "%s: failed to add XHCI pdev ret=%d\n", __func__, ret); regulator_disable(dotg->vbus_otg); dwc3_otg_notify_host_mode(otg, 0); return ret; } /* re-init OTG EVTEN register as XHCI reset clears it */ if (ext_xceiv && !ext_xceiv->otg_capability) 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; } dwc3_otg_notify_host_mode(otg, on); platform_device_del(dwc->xhci); /* * Perform USB hardware RESET (both core reset and DBM reset) * when moving from host to peripheral. This is required for * peripheral mode to work. */ if (ext_xceiv && ext_xceiv->otg_capability && ext_xceiv->ext_block_reset) ext_xceiv->ext_block_reset(ext_xceiv, true); dwc3_otg_set_hsphy_auto_suspend(dotg, false); dwc3_otg_set_peripheral_regs(dotg); /* re-init core and OTG registers as block reset clears these */ dwc3_post_host_reset_core_init(dwc); if (ext_xceiv && !ext_xceiv->otg_capability) dwc3_otg_reset(dotg); } return 0; }
static int dwc3_otg_start_host(struct usb_otg *otg, int on) { struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg); struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv; struct dwc3 *dwc = dotg->dwc; int ret = 0; #ifdef CONFIG_PANTECH_QUALCOMM_OTG_MODE_OVP_BUG //xsemiyas_debug int value; #endif #if defined(CONFIG_PANTECH_USB_SMB_OTG_DISABLE_LOW_BATTERY) || defined(CONFIG_PANTECH_USB_TI_OTG_DISABLE_LOW_BATTERY) int level; #endif if (!dwc->xhci) return -EINVAL; #ifdef FEATURE_PANTECH_USB_CHARGER_INIT_ERROR if(!charger_ready_status()) return -ENODEV; #endif #if !defined(CONFIG_PANTECH_PMIC_CHARGER_SMB347) && !defined(CONFIG_PANTECH_PMIC_CHARGER_SMB349) && !defined(CONFIG_PANTECH_PMIC_CHARGER_BQ2419X) 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; } } #endif /* !defined(CONFIG_PANTECH_PMIC_CHARGER_SMB347) && !defined(CONFIG_PANTECH_PMIC_CHARGER_SMB349) && !defined(CONFIG_PANTECH_CHARGER_BQ2419X) */ #if defined(CONFIG_PANTECH_USB_SMB_OTG_DISABLE_LOW_BATTERY) && defined(CONFIG_PANTECH_PMIC_OTG_UVLO) level = max17058_get_soc_for_otg(); #elif defined(CONFIG_PANTECH_USB_TI_OTG_DISABLE_LOW_BATTERY) && defined(CONFIG_PANTECH_EF63_PMIC_FUELGAUGE_MAX17058) level = max17058_get_soc_for_led(); #else level = 50; #endif if (on) { dev_dbg(otg->phy->dev, "%s: turn on host\n", __func__); #if defined(CONFIG_PANTECH_PMIC_CHARGER_SMB347) || defined(CONFIG_PANTECH_PMIC_CHARGER_SMB349) //xsemiyas_debug:warmup_time smb349_otg_power(1); usleep_range(60, 100); #ifdef CONFIG_PANTECH_PMIC_OTG smb349_otg_power_current(3); #endif /* CONFIG_PANTECH_PMIC_OTG */ smb349_otg_power(0); #endif /* defined(CONFIG_PANTECH_PMIC_CHARGER_SMB347) || defined(CONFIG_PANTECH_PMIC_CHARGER_SMB349) */ /* * This should be revisited for more testing post-silicon. * In worst case we may need to disconnect the root hub * before stopping the controller so that it does not * interfere with runtime pm/system pm. * We can also consider registering and unregistering xhci * platform device. It is almost similar to add_hcd and * remove_hcd, But we may not use standard set_host method * anymore. */ dwc3_otg_set_hsphy_auto_suspend(dotg, true); dwc3_otg_set_host_regs(dotg); /* * FIXME If micro A cable is disconnected during system suspend, * xhci platform device will be removed before runtime pm is * enabled for xhci device. Due to this, disable_depth becomes * greater than one and runtimepm is not enabled for next microA * connect. Fix this by calling pm_runtime_init for xhci device. */ pm_runtime_init(&dwc->xhci->dev); ret = platform_device_add(dwc->xhci); if (ret) { dev_err(otg->phy->dev, "%s: failed to add XHCI pdev ret=%d\n", __func__, ret); return ret; } dwc3_otg_notify_host_mode(otg, on); #ifdef CONFIG_PANTECH_QUALCOMM_OTG_MODE_OVP_BUG //xsemiyas_debug while((value = get_pantech_chg_otg_mode()) != 1){ if(value == -1){ set_pantech_chg_otg_mode(0); dev_err(otg->phy->dev, "unable to enable qpnp_otg_mode\n"); return -ENXIO; } msleep(10); } #endif #if defined(CONFIG_PANTECH_USB_SMB_OTG_DISABLE_LOW_BATTERY) if (level < 30) { dev_err(dwc->dev, "Low Battery!!, OTG power not set!\n"); #ifdef CONFIG_ANDROID_PANTECH_USB_OTG_INTENT set_otg_dev_state(2); #endif return 0; } #elif defined(CONFIG_PANTECH_USB_TI_OTG_DISABLE_LOW_BATTERY) if (level < 10) { dev_err(dwc->dev, "Battery is not enough!, OTG power remove!\n"); #ifdef CONFIG_ANDROID_PANTECH_USB_OTG_INTENT set_otg_dev_state(2); #endif #if defined(CONFIG_PANTECH_PMIC_CHARGER_BQ2419X) //chg_force_switching_scope(1); //otg power remove dwc3_otg_notify_host_mode(otg, 0); //otg power remove #endif return 0; } #endif #ifdef CONFIG_PANTECH_USB_TUNE_SIGNALING_PARAM pantech_set_otg_signaling_param(on); #endif #if defined(CONFIG_PANTECH_PMIC_CHARGER_SMB347) || defined(CONFIG_PANTECH_PMIC_CHARGER_SMB349) smb349_otg_power(on); #ifdef CONFIG_PANTECH_PMIC_OTG usleep_range(60, 100);//xsemiyas_debug: change 60uS smb349_otg_power_current(3); //750mA current setting #endif /* CONFIG_PANTECH_PMIC_OTG */ #elif !defined(CONFIG_PANTECH_PMIC_CHARGER_BQ2419X) ret = regulator_enable(dotg->vbus_otg); if (ret) { dev_err(otg->phy->dev, "unable to enable vbus_otg\n"); platform_device_del(dwc->xhci); return ret; } #endif /* defined(CONFIG_PANTECH_PMIC_CHARGER_SMB347) || defined(CONFIG_PANTECH_PMIC_CHARGER_SMB349) */ /* re-init OTG EVTEN register as XHCI reset clears it */ if (ext_xceiv && !ext_xceiv->otg_capability) dwc3_otg_reset(dotg); #if defined(CONFIG_PANTECH_USB_SMB_OTG_DISABLE_LOW_BATTERY) || defined(CONFIG_PANTECH_USB_TI_OTG_DISABLE_LOW_BATTERY) is_otg_enabled = 1; #endif } else { dev_dbg(otg->phy->dev, "%s: turn off host\n", __func__); #ifdef CONFIG_PANTECH_USB_SMB_OTG_DISABLE_LOW_BATTERY if (level >= 30) { #endif #if defined(CONFIG_PANTECH_PMIC_CHARGER_SMB347) || defined(CONFIG_PANTECH_PMIC_CHARGER_SMB349) smb349_otg_power(on); #ifdef CONFIG_PANTECH_PMIC_OTG smb349_otg_power_current(1); //250mA current setting #endif /* CONFIG_PANTECH_PMIC_OTG */ #ifdef CONFIG_PANTECH_USB_SMB_OTG_DISABLE_LOW_BATTERY } #endif #elif !defined(CONFIG_PANTECH_PMIC_CHARGER_BQ2419X) ret = regulator_disable(dotg->vbus_otg); if (ret) { dev_err(otg->phy->dev, "unable to disable vbus_otg\n"); return ret; } #endif /* defined(CONFIG_PANTECH_PMIC_CHARGER_SMB347) || defined(CONFIG_PANTECH_PMIC_CHARGER_SMB349) */ #ifdef CONFIG_PANTECH_USB_TUNE_SIGNALING_PARAM pantech_set_otg_signaling_param(on); #endif #if defined(CONFIG_PANTECH_USB_SMB_OTG_DISABLE_LOW_BATTERY) || defined(CONFIG_PANTECH_USB_TI_OTG_DISABLE_LOW_BATTERY) is_otg_enabled = 0; #endif dwc3_otg_notify_host_mode(otg, on); #ifdef CONFIG_PANTECH_SIO_BUG_FIX /* FIXME : Sometimes sm_work is executed twice in abnormal state. * So platform_device_del is executed twice. * And this code is occurred NULL pointer exception at seconds procedure. * We are fixed below code only executed one. * from LS4-USB tarial */ if (dwc->xhci) platform_device_del(dwc->xhci); #else platform_device_del(dwc->xhci); #endif /* * Perform USB hardware RESET (both core reset and DBM reset) * when moving from host to peripheral. This is required for * peripheral mode to work. */ if (ext_xceiv && ext_xceiv->otg_capability && ext_xceiv->ext_block_reset) ext_xceiv->ext_block_reset(ext_xceiv, true); dwc3_otg_set_hsphy_auto_suspend(dotg, false); dwc3_otg_set_peripheral_regs(dotg); /* re-init core and OTG registers as block reset clears these */ dwc3_post_host_reset_core_init(dwc); if (ext_xceiv && !ext_xceiv->otg_capability) dwc3_otg_reset(dotg); } return 0; }
/** * dwc3_otg_start_host - helper function for starting/stoping the host controller driver. * * @otg: Pointer to the otg_transceiver structure. * @on: start / stop the host controller driver. * * Returns 0 on success otherwise negative errno. */ static int dwc3_otg_start_host(struct usb_otg *otg, int on) { struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg); struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv; struct dwc3 *dwc = dotg->dwc; int ret = 0; 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 (on) { dev_dbg(otg->phy->dev, "%s: turn on host\n", __func__); /* * This should be revisited for more testing post-silicon. * In worst case we may need to disconnect the root hub * before stopping the controller so that it does not * interfere with runtime pm/system pm. * We can also consider registering and unregistering xhci * platform device. It is almost similar to add_hcd and * remove_hcd, But we may not use standard set_host method * anymore. */ dwc3_otg_set_host_regs(dotg); ret = platform_device_add(dwc->xhci); if (ret) { dev_err(otg->phy->dev, "%s: failed to add XHCI pdev ret=%d\n", __func__, ret); return ret; } dwc3_otg_notify_host_mode(otg, on); ret = regulator_enable(dotg->vbus_otg); if (ret) { dev_err(otg->phy->dev, "unable to enable vbus_otg\n"); platform_device_del(dwc->xhci); return ret; } /* re-init OTG EVTEN register as XHCI reset clears it */ if (ext_xceiv && !ext_xceiv->otg_capability) dwc3_otg_reset(dotg); } else { dev_dbg(otg->phy->dev, "%s: turn off host\n", __func__); platform_device_del(dwc->xhci); ret = regulator_disable(dotg->vbus_otg); if (ret) { dev_err(otg->phy->dev, "unable to disable vbus_otg\n"); return ret; } dwc3_otg_notify_host_mode(otg, on); } return 0; }
/** * dwc3_otg_start_host - helper function for starting/stoping the host controller driver. * * @otg: Pointer to the otg_transceiver structure. * @on: start / stop the host controller driver. * * Returns 0 on success otherwise negative errno. */ static int dwc3_otg_start_host(struct usb_otg *otg, int on) { struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg); struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv; struct dwc3 *dwc = dotg->dwc; struct usb_hcd *hcd; int ret = 0; 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 (on) { dev_dbg(otg->phy->dev, "%s: turn on host\n", __func__); dwc3_otg_notify_host_mode(otg, on); usb_phy_notify_connect(dotg->dwc->usb2_phy, USB_SPEED_HIGH); 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; } dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); /* * FIXME If micro A cable is disconnected during system suspend, * xhci platform device will be removed before runtime pm is * enabled for xhci device. Due to this, disable_depth becomes * greater than one and runtimepm is not enabled for next microA * connect. Fix this by calling pm_runtime_init for xhci device. */ pm_runtime_init(&dwc->xhci->dev); ret = platform_device_add(dwc->xhci); if (ret) { dev_err(otg->phy->dev, "%s: failed to add XHCI pdev ret=%d\n", __func__, ret); regulator_disable(dotg->vbus_otg); dwc3_otg_notify_host_mode(otg, 0); return ret; } /* * WORKAROUND: currently host mode suspend isn't working well. * Disable xHCI's runtime PM for now. */ pm_runtime_disable(&dwc->xhci->dev); hcd = platform_get_drvdata(dwc->xhci); otg->host = &hcd->self; dwc3_gadget_usb3_phy_suspend(dwc, true); } 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; } dbg_event(0xFF, "StHost get", 0); pm_runtime_get(dwc->dev); usb_phy_notify_disconnect(dotg->dwc->usb2_phy, USB_SPEED_HIGH); dwc3_otg_notify_host_mode(otg, on); otg->host = NULL; platform_device_del(dwc->xhci); /* * Perform USB hardware RESET (both core reset and DBM reset) * when moving from host to peripheral. This is required for * peripheral mode to work. */ if (ext_xceiv && ext_xceiv->ext_block_reset) ext_xceiv->ext_block_reset(ext_xceiv, true); dwc3_gadget_usb3_phy_suspend(dwc, false); dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); /* re-init core and OTG registers as block reset clears these */ dwc3_post_host_reset_core_init(dwc); dbg_event(0xFF, "StHost put", 0); pm_runtime_put(dwc->dev); } return 0; }
/** * dwc3_otg_start_host - helper function for starting/stoping the host controller driver. * * @otg: Pointer to the otg_transceiver structure. * @on: start / stop the host controller driver. * * Returns 0 on success otherwise negative errno. */ static int dwc3_otg_start_host(struct usb_otg *otg, int on) { struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg); struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv; struct dwc3 *dwc = dotg->dwc; struct usb_hcd *hcd; int ret = 0; 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 (on) { dev_dbg(otg->phy->dev, "%s: turn on host\n", __func__); dwc3_otg_notify_host_mode(otg, on); usb_phy_notify_connect(dotg->dwc->usb2_phy, USB_SPEED_HIGH); /* register ocp notification */ if (ext_xceiv && 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. */ usleep(10000); dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); /* * FIXME If micro A cable is disconnected during system suspend, * xhci platform device will be removed before runtime pm is * enabled for xhci device. Due to this, disable_depth becomes * greater than one and runtimepm is not enabled for next microA * connect. Fix this by calling pm_runtime_init for xhci device. */ pm_runtime_init(&dwc->xhci->dev); ret = platform_device_add(dwc->xhci); if (ret) { dev_err(otg->phy->dev, "%s: failed to add XHCI pdev ret=%d\n", __func__, ret); regulator_disable(dotg->vbus_otg); dwc3_otg_notify_host_mode(otg, 0); return ret; } /* * WORKAROUND: avoids entering a suspend state, because PMIC * is damaged by known issue when attempt to suspend. */ wake_lock(&dotg->host_wakelock); /* * WORKAROUND: currently host mode suspend isn't working well. * Disable xHCI's runtime PM for now. */ pm_runtime_disable(&dwc->xhci->dev); if (no_device_timeout_enable) { dotg->no_device_timeout_enabled = 1; dotg->device_count = 0; dotg->retry_count = 0; dotg->usbdev_nb.notifier_call = dwc3_usbdev_notify; usb_register_notify(&dotg->usbdev_nb); dwc3_otg_start_no_device_work(dotg, true); } hcd = platform_get_drvdata(dwc->xhci); otg->host = &hcd->self; dwc3_gadget_usb3_phy_suspend(dwc, true); } 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; } dbg_event(0xFF, "StHost get", 0); /* unregister ocp notification */ if (ext_xceiv && 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"); } pm_runtime_get(dwc->dev); usb_phy_notify_disconnect(dotg->dwc->usb2_phy, USB_SPEED_HIGH); dwc3_otg_notify_host_mode(otg, on); otg->host = NULL; if (dotg->no_device_timeout_enabled) { dotg->no_device_timeout_enabled = 0; dwc3_otg_start_no_device_work(dotg, false); usb_unregister_notify(&dotg->usbdev_nb); } platform_device_del(dwc->xhci); /* WORKAROUND: delays execution of the block-reset because it * causes HWWD if ext_xceive access the HW during block reset. */ usleep(10000); if (wake_lock_active(&dotg->host_wakelock)) wake_unlock(&dotg->host_wakelock); /* * Perform USB hardware RESET (both core reset and DBM reset) * when moving from host to peripheral. This is required for * peripheral mode to work. */ if (ext_xceiv && ext_xceiv->ext_block_reset) ext_xceiv->ext_block_reset(ext_xceiv, true); dwc3_gadget_usb3_phy_suspend(dwc, false); dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); /* re-init core and OTG registers as block reset clears these */ dwc3_post_host_reset_core_init(dwc); dbg_event(0xFF, "StHost put", 0); pm_runtime_put(dwc->dev); } return 0; }