diff options
Diffstat (limited to 'drivers/usb/phy/phy-msm-qusb-v2.c')
| -rw-r--r-- | drivers/usb/phy/phy-msm-qusb-v2.c | 104 |
1 files changed, 58 insertions, 46 deletions
diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c index 5df091a5454b..de4f93afdc97 100644 --- a/drivers/usb/phy/phy-msm-qusb-v2.c +++ b/drivers/usb/phy/phy-msm-qusb-v2.c @@ -76,6 +76,7 @@ MODULE_PARM_DESC(phy_tune1, "QUSB PHY v2 TUNE1"); struct qusb_phy { struct usb_phy phy; + struct mutex lock; void __iomem *base; void __iomem *efuse_reg; void __iomem *tcsr_clamp_dig_n; @@ -100,7 +101,7 @@ struct qusb_phy { int efuse_bit_pos; int efuse_num_of_bits; - bool power_enabled; + int power_enabled_ref; bool clocks_enabled; bool cable_connected; bool suspended; @@ -160,35 +161,47 @@ static int qusb_phy_config_vdd(struct qusb_phy *qphy, int high) return ret; } -static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on, - bool toggle_vdd) +static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on) { int ret = 0; - dev_dbg(qphy->phy.dev, "%s turn %s regulators. power_enabled:%d\n", - __func__, on ? "on" : "off", qphy->power_enabled); + mutex_lock(&qphy->lock); - if (toggle_vdd && qphy->power_enabled == on) { - dev_dbg(qphy->phy.dev, "PHYs' regulators are already ON.\n"); - return 0; - } + dev_dbg(qphy->phy.dev, + "%s:req to turn %s regulators. power_enabled_ref:%d\n", + __func__, on ? "on" : "off", qphy->power_enabled_ref); - if (!on) - goto disable_vdda33; + if (on && ++qphy->power_enabled_ref > 1) { + dev_dbg(qphy->phy.dev, "PHYs' regulators are already on\n"); + goto done; + } - if (toggle_vdd) { - ret = qusb_phy_config_vdd(qphy, true); - if (ret) { - dev_err(qphy->phy.dev, "Unable to config VDD:%d\n", - ret); - goto err_vdd; + if (!on) { + if (on == qphy->power_enabled_ref) { + dev_dbg(qphy->phy.dev, + "PHYs' regulators are already off\n"); + goto done; } - ret = regulator_enable(qphy->vdd); - if (ret) { - dev_err(qphy->phy.dev, "Unable to enable VDD\n"); - goto unconfig_vdd; - } + qphy->power_enabled_ref--; + if (!qphy->power_enabled_ref) + goto disable_vdda33; + + dev_dbg(qphy->phy.dev, "Skip turning off PHYs' regulators\n"); + goto done; + } + + ret = qusb_phy_config_vdd(qphy, true); + if (ret) { + dev_err(qphy->phy.dev, "Unable to config VDD:%d\n", + ret); + goto err_vdd; + } + + ret = regulator_enable(qphy->vdd); + if (ret) { + dev_err(qphy->phy.dev, "Unable to enable VDD\n"); + goto unconfig_vdd; } ret = regulator_set_load(qphy->vdda12, QUSB2PHY_1P2_HPM_LOAD); @@ -251,10 +264,9 @@ static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on, goto unset_vdd33; } - if (toggle_vdd) - qphy->power_enabled = true; - pr_debug("%s(): QUSB PHY's regulators are turned ON.\n", __func__); + + mutex_unlock(&qphy->lock); return ret; disable_vdda33: @@ -304,22 +316,24 @@ put_vdda12_lpm: dev_err(qphy->phy.dev, "Unable to set LPM of vdda12\n"); disable_vdd: - if (toggle_vdd) { - ret = regulator_disable(qphy->vdd); - if (ret) - dev_err(qphy->phy.dev, "Unable to disable vdd:%d\n", - ret); + ret = regulator_disable(qphy->vdd); + if (ret) + dev_err(qphy->phy.dev, "Unable to disable vdd:%d\n", + ret); unconfig_vdd: - ret = qusb_phy_config_vdd(qphy, false); - if (ret) - dev_err(qphy->phy.dev, "Unable unconfig VDD:%d\n", - ret); - } + ret = qusb_phy_config_vdd(qphy, false); + if (ret) + dev_err(qphy->phy.dev, "Unable unconfig VDD:%d\n", + ret); err_vdd: - if (toggle_vdd) - qphy->power_enabled = false; dev_dbg(qphy->phy.dev, "QUSB PHY's regulators are turned OFF.\n"); + + /* in case of error in turning on regulators */ + if (qphy->power_enabled_ref) + qphy->power_enabled_ref--; +done: + mutex_unlock(&qphy->lock); return ret; } @@ -335,7 +349,7 @@ static int qusb_phy_update_dpdm(struct usb_phy *phy, int value) case POWER_SUPPLY_DP_DM_DPF_DMF: dev_dbg(phy->dev, "POWER_SUPPLY_DP_DM_DPF_DMF\n"); if (!qphy->rm_pulldown) { - ret = qusb_phy_enable_power(qphy, true, false); + ret = qusb_phy_enable_power(qphy, true); if (ret >= 0) { qphy->rm_pulldown = true; dev_dbg(phy->dev, "DP_DM_F: rm_pulldown:%d\n", @@ -348,7 +362,7 @@ static int qusb_phy_update_dpdm(struct usb_phy *phy, int value) case POWER_SUPPLY_DP_DM_DPR_DMR: dev_dbg(phy->dev, "POWER_SUPPLY_DP_DM_DPR_DMR\n"); if (qphy->rm_pulldown) { - ret = qusb_phy_enable_power(qphy, false, false); + ret = qusb_phy_enable_power(qphy, false); if (ret >= 0) { qphy->rm_pulldown = false; dev_dbg(phy->dev, "DP_DM_R: rm_pulldown:%d\n", @@ -452,10 +466,6 @@ static int qusb_phy_init(struct usb_phy *phy) dev_dbg(phy->dev, "%s\n", __func__); - ret = qusb_phy_enable_power(qphy, true, true); - if (ret) - return ret; - /* bump up vdda33 voltage to operating level*/ ret = regulator_set_voltage(qphy->vdda33, qphy->vdda33_levels[1], qphy->vdda33_levels[2]); @@ -683,7 +693,7 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) wmb(); qusb_phy_enable_clocks(qphy, false); - qusb_phy_enable_power(qphy, false, true); + qusb_phy_enable_power(qphy, false); } qphy->suspended = true; } else { @@ -715,7 +725,7 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) */ wmb(); - qusb_phy_enable_power(qphy, true, true); + qusb_phy_enable_power(qphy, true); ret = reset_control_assert(qphy->phy_reset); if (ret) dev_err(phy->dev, "%s: phy_reset assert failed\n", @@ -1063,6 +1073,8 @@ static int qusb_phy_probe(struct platform_device *pdev) return PTR_ERR(qphy->vdda12); } + mutex_init(&qphy->lock); + platform_set_drvdata(pdev, qphy); qphy->phy.label = "msm-qusb-phy-v2"; @@ -1100,7 +1112,7 @@ static int qusb_phy_remove(struct platform_device *pdev) qphy->clocks_enabled = false; } - qusb_phy_enable_power(qphy, false, true); + qusb_phy_enable_power(qphy, false); return 0; } |
