summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/regulator/qpnp-labibb-regulator.c126
1 files changed, 72 insertions, 54 deletions
diff --git a/drivers/regulator/qpnp-labibb-regulator.c b/drivers/regulator/qpnp-labibb-regulator.c
index dad82b43ea6e..de4614d4d1ef 100644
--- a/drivers/regulator/qpnp-labibb-regulator.c
+++ b/drivers/regulator/qpnp-labibb-regulator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -162,6 +162,7 @@
#define IBB_MODULE_RDY_EN BIT(7)
/* REG_IBB_ENABLE_CTL */
+#define IBB_ENABLE_CTL_MASK (BIT(7) | BIT(6))
#define IBB_ENABLE_CTL_SWIRE_RDY BIT(6)
#define IBB_ENABLE_CTL_MODULE_EN BIT(7)
@@ -245,6 +246,17 @@ enum qpnp_labibb_mode {
QPNP_LABIBB_MAX_MODE,
};
+/**
+ * IBB_SW_CONTROL_EN: Specifies IBB is enabled through software.
+ * IBB_SW_CONTROL_DIS: Specifies IBB is disabled through software.
+ * IBB_HW_CONTROL: Specifies IBB is controlled through SWIRE (hardware).
+ */
+enum ibb_mode {
+ IBB_SW_CONTROL_EN,
+ IBB_SW_CONTROL_DIS,
+ IBB_HW_CONTROL,
+};
+
static const int ibb_discharge_resistor_plan[] = {
300,
64,
@@ -596,6 +608,29 @@ static int qpnp_labibb_get_matching_idx(const char *val)
return -EINVAL;
}
+static int qpnp_ibb_set_mode(struct qpnp_labibb *labibb, enum ibb_mode mode)
+{
+ int rc;
+ u8 val;
+
+ if (mode == IBB_SW_CONTROL_EN)
+ val = IBB_ENABLE_CTL_MODULE_EN;
+ else if (mode == IBB_HW_CONTROL)
+ val = IBB_ENABLE_CTL_SWIRE_RDY;
+ else if (mode == IBB_SW_CONTROL_DIS)
+ val = 0;
+ else
+ return -EINVAL;
+
+ rc = qpnp_labibb_masked_write(labibb,
+ labibb->ibb_base + REG_IBB_ENABLE_CTL,
+ IBB_ENABLE_CTL_MASK, val);
+ if (rc)
+ pr_err("Unable to configure IBB_ENABLE_CTL rc=%d\n", rc);
+
+ return rc;
+}
+
static int qpnp_lab_dt_init(struct qpnp_labibb *labibb,
struct device_node *of_node)
{
@@ -837,9 +872,7 @@ static int qpnp_lab_dt_init(struct qpnp_labibb *labibb,
}
if (labibb->swire_control) {
- val = IBB_ENABLE_CTL_SWIRE_RDY;
- rc = qpnp_labibb_write(labibb,
- labibb->ibb_base + REG_IBB_ENABLE_CTL, &val, 1);
+ rc = qpnp_ibb_set_mode(labibb, IBB_HW_CONTROL);
if (rc)
pr_err("Unable to set SWIRE_RDY rc=%d\n", rc);
}
@@ -1016,12 +1049,9 @@ static int qpnp_labibb_regulator_ttw_mode_enter(struct qpnp_labibb *labibb)
return rc;
}
- val = IBB_ENABLE_CTL_SWIRE_RDY;
- rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL,
- &val, 1);
+ rc = qpnp_ibb_set_mode(labibb, IBB_HW_CONTROL);
if (rc) {
- pr_err("qpnp_labibb_write register %x failed rc = %d\n",
- REG_IBB_ENABLE_CTL, rc);
+ pr_err("Unable to set SWIRE_RDY rc = %d\n", rc);
return rc;
}
labibb->in_ttw_mode = true;
@@ -1072,16 +1102,6 @@ static int qpnp_labibb_regulator_ttw_mode_exit(struct qpnp_labibb *labibb)
return rc;
}
- val = 0;
- rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL,
- &val, 1);
-
- if (rc) {
- pr_err("qpnp_labibb_write register %x failed rc = %d\n",
- REG_IBB_ENABLE_CTL, rc);
- return rc;
- }
-
labibb->in_ttw_mode = false;
return rc;
}
@@ -1089,7 +1109,7 @@ static int qpnp_labibb_regulator_ttw_mode_exit(struct qpnp_labibb *labibb)
static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb)
{
int rc;
- u8 val = IBB_ENABLE_CTL_MODULE_EN;
+ u8 val;
int dly;
int retries;
bool enabled = false;
@@ -1103,12 +1123,9 @@ static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb)
}
}
- rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL,
- &val, 1);
-
+ rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_EN);
if (rc) {
- pr_err("write register %x failed rc = %d\n",
- REG_IBB_ENABLE_CTL, rc);
+ pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc);
return rc;
}
@@ -1164,12 +1181,11 @@ static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb)
return 0;
err_out:
- val = 0;
- rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL,
- &val, 1);
- if (rc)
- pr_err("write register %x failed rc = %d\n",
- REG_IBB_ENABLE_CTL, rc);
+ rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_DIS);
+ if (rc) {
+ pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc);
+ return rc;
+ }
return -EINVAL;
}
@@ -1181,12 +1197,28 @@ static int qpnp_labibb_regulator_disable(struct qpnp_labibb *labibb)
int retries;
bool disabled = false;
- val = 0;
- rc = qpnp_labibb_write(labibb,
- labibb->ibb_base + REG_IBB_ENABLE_CTL, &val, 1);
+ /*
+ * When TTW mode is enabled and LABIBB regulators are disabled, it is
+ * recommended not to disable IBB through IBB_ENABLE_CTL when switching
+ * to SWIRE control on entering TTW mode. Hence, just enter TTW mode
+ * and mark the regulators disabled. When we exit TTW mode, normal
+ * mode settings will be restored anyways and regulators will be
+ * enabled as before.
+ */
+ if (labibb->ttw_en && !labibb->in_ttw_mode) {
+ rc = qpnp_labibb_regulator_ttw_mode_enter(labibb);
+ if (rc) {
+ pr_err("Error in entering TTW mode rc = %d\n", rc);
+ return rc;
+ }
+ labibb->lab_vreg.vreg_enabled = 0;
+ labibb->ibb_vreg.vreg_enabled = 0;
+ return 0;
+ }
+
+ rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_DIS);
if (rc) {
- pr_err("write register %x failed rc = %d\n",
- REG_IBB_ENABLE_CTL, rc);
+ pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc);
return rc;
}
@@ -1217,13 +1249,6 @@ static int qpnp_labibb_regulator_disable(struct qpnp_labibb *labibb)
labibb->lab_vreg.vreg_enabled = 0;
labibb->ibb_vreg.vreg_enabled = 0;
- if (labibb->ttw_en && !labibb->in_ttw_mode) {
- rc = qpnp_labibb_regulator_ttw_mode_enter(labibb);
- if (rc) {
- pr_err("Error in entering TTW mode rc = %d\n", rc);
- return rc;
- }
- }
return 0;
}
@@ -1912,12 +1937,9 @@ static int qpnp_ibb_regulator_enable(struct regulator_dev *rdev)
if (labibb->mode != QPNP_LABIBB_STANDALONE_MODE)
return qpnp_labibb_regulator_enable(labibb);
- val = IBB_ENABLE_CTL_MODULE_EN;
- rc = qpnp_labibb_write(labibb,
- labibb->ibb_base + REG_IBB_ENABLE_CTL, &val, 1);
+ rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_EN);
if (rc) {
- pr_err("qpnp_ibb_regulator_enable write register %x failed rc = %d\n",
- REG_IBB_ENABLE_CTL, rc);
+ pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc);
return rc;
}
@@ -1944,7 +1966,6 @@ static int qpnp_ibb_regulator_enable(struct regulator_dev *rdev)
static int qpnp_ibb_regulator_disable(struct regulator_dev *rdev)
{
int rc;
- u8 val;
struct qpnp_labibb *labibb = rdev_get_drvdata(rdev);
if (labibb->ibb_vreg.vreg_enabled && !labibb->swire_control) {
@@ -1952,12 +1973,9 @@ static int qpnp_ibb_regulator_disable(struct regulator_dev *rdev)
if (labibb->mode != QPNP_LABIBB_STANDALONE_MODE)
return qpnp_labibb_regulator_disable(labibb);
- val = 0;
- rc = qpnp_labibb_write(labibb, labibb->ibb_base +
- REG_IBB_ENABLE_CTL, &val, 1);
+ rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_DIS);
if (rc) {
- pr_err("qpnp_ibb_regulator_enable write register %x failed rc = %d\n",
- REG_IBB_ENABLE_CTL, rc);
+ pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc);
return rc;
}