summaryrefslogtreecommitdiff
path: root/drivers/usb/phy/phy-msm-qusb-v2.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/phy/phy-msm-qusb-v2.c')
-rw-r--r--drivers/usb/phy/phy-msm-qusb-v2.c104
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;
}