regulator: qpnp-labibb: do not disable IBB when entering TTW mode

Currently when entering touch-to-wakeup (TTW) mode, IBB module
is disabled as part of the regulator_disable sequence before
applying the settings needed for SWIRE control in TTW mode.
This causes adversary effects such as droop in the VDISN
voltage rail.

To avoid this, as per the hardware documentation, do not disable
IBB module through IBB_ENABLE_CTL when LABIBB regulators are
disabled and entering TTW mode. Instead, just enter TTW mode and
mark the regulators disabled. Normal mode settings will be
applied when the regulators are enabled again as before.

While at it, add a centralized function qpnp_ibb_mode() to write
to IBB_ENABLE_CTL register.

CRs-Fixed: 952847
Change-Id: I74c6ba411091d146ab5719c2d72d6385fa90af21
Signed-off-by: Subbaraman Narayanamurthy <subbaram@codeaurora.org>
This commit is contained in:
Subbaraman Narayanamurthy 2015-12-22 12:23:49 -08:00 committed by Gerrit - the friendly Code Review server
parent 44626b79a8
commit 8ac740251d
1 changed files with 72 additions and 54 deletions

View File

@ -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
@ -159,6 +159,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)
@ -232,6 +233,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,
@ -595,6 +607,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, 1);
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;
}
@ -2158,12 +2183,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;
}
@ -2190,7 +2212,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) {
@ -2198,12 +2219,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;
}