regulator: qpnp-labibb: Add support for controlling IBB pulse skip timing

The IBB pulse-skip and NLIMIT DAC configuration should be disabled
before applying the 2nd SWIRE command skip logic, to guarantee
that the IBB voltage changes immediately in the subsequent
SWIRE command. After the WA is completed, the pulse-skip can
be re-enabled after a programmable delay. Add this logic and
a DT property 'qcom,swire-ibb-ps-enable-delay' to configure
this delay. If this delay is not specified in the DT it defaults
to 200ms.

CRs-Fixed: 1010085
Change-Id: Ifec458a0028c16440ffd6ac1f6fa58eebc815c5a
Signed-off-by: Anirudh Ghayal <aghayal@codeaurora.org>
This commit is contained in:
Anirudh Ghayal 2016-05-03 22:34:07 +05:30 committed by Kyle Yan
parent a492035331
commit 3358aae869
2 changed files with 62 additions and 53 deletions

View file

@ -33,11 +33,17 @@ Main node optional properties:
always on during TTW mode.
- qcom,skip-2nd-swire-cmd: A boolean property which indicates if
the second SWIRE command needs to be skipped.
- qcom,swire-2nd-cmd-delay: A integer value which specifes the
- qcom,swire-2nd-cmd-delay: An integer value which specifes the
delay in millisecs between the first and second
SWIRE command. If not specified this value
defaults to 20ms. This delay is applied only
if 'qpnp,skip-2nd-swire-cmd' is defined.
if 'qcom,skip-2nd-swire-cmd' is defined.
- qcom,swire-ibb-ps-enable-delay: An integer value which specifes the delay
in millisecs to enable IBB pulse-skipping
after the skip-2nd-swire-cmd workaround is applied.
If not specified this value default to 200ms.
This property is applicable only if
'qcom,skip-2nd-swire-cmd' is specified.
- qcom,labibb-standalone: A boolean property which forces LAB and
IBB to operate in standalone mode. If
this is not specified, then LAB and IBB

View file

@ -250,7 +250,8 @@
#define IBB_WAIT_MBG_OK BIT(2)
/* Constants */
#define SWIRE_DEFAULT_2ND_CMD_DLY_MS 20
#define SWIRE_DEFAULT_2ND_CMD_DLY_MS 20
#define SWIRE_DEFAULT_IBB_PS_ENABLE_DLY_MS 200
enum pmic_subtype {
PMI8994 = 10,
@ -487,6 +488,7 @@ struct qpnp_labibb {
bool ttw_force_lab_on;
bool skip_2nd_swire_cmd;
u32 swire_2nd_cmd_delay;
u32 swire_ibb_ps_enable_delay;
};
enum ibb_settings_index {
@ -677,6 +679,29 @@ static int qpnp_ibb_set_mode(struct qpnp_labibb *labibb, enum ibb_mode mode)
return rc;
}
static int qpnp_ibb_ps_config(struct qpnp_labibb *labibb, bool enable)
{
u8 val;
int rc;
val = enable ? IBB_PS_CTL_EN : IBB_PS_CTL_DISABLE;
rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_PS_CTL,
&val, 1);
if (rc) {
pr_err("qpnp_ibb_ps_config write register %x failed rc = %d\n",
REG_IBB_PS_CTL, rc);
return rc;
}
val = enable ? IBB_NLIMIT_DAC_EN : IBB_NLIMIT_DAC_DISABLE;
rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_NLIMIT_DAC,
&val, 1);
if (rc)
pr_err("qpnp_ibb_ps_config write register %x failed rc = %d\n",
REG_IBB_NLIMIT_DAC, rc);
return rc;
}
static int qpnp_lab_dt_init(struct qpnp_labibb *labibb,
struct device_node *of_node)
{
@ -1057,21 +1082,9 @@ static int qpnp_labibb_ttw_enter_ibb_pmi8950(struct qpnp_labibb *labibb)
int rc;
u8 val;
val = 0;
rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_NLIMIT_DAC,
&val, 1);
rc = qpnp_ibb_ps_config(labibb, true);
if (rc) {
pr_err("qpnp_labibb_write register %x failed rc = %d\n",
REG_IBB_NLIMIT_DAC, rc);
return rc;
}
val = IBB_PS_CTL_EN;
rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_PS_CTL,
&val, 1);
if (rc) {
pr_err("qpnp_labibb_write register %x failed rc = %d\n",
REG_IBB_PS_CTL, rc);
pr_err("Failed to enable ibb_ps_config rc=%d\n", rc);
return rc;
}
@ -1437,6 +1450,14 @@ static int qpnp_lab_regulator_enable(struct regulator_dev *rdev)
struct qpnp_labibb *labibb = rdev_get_drvdata(rdev);
if (labibb->skip_2nd_swire_cmd) {
rc = qpnp_ibb_ps_config(labibb, false);
if (rc) {
pr_err("Failed to disable IBB PS rc=%d\n", rc);
return rc;
}
}
if (!labibb->lab_vreg.vreg_enabled && !labibb->swire_control) {
if (!labibb->standalone)
@ -1611,6 +1632,12 @@ static int qpnp_skip_swire_command(struct qpnp_labibb *labibb)
if (rc)
pr_err("Failed switch to IBB_HW_CONTROL rc=%d\n", rc);
/* delay before enabling the PS mode */
msleep(labibb->swire_ibb_ps_enable_delay);
rc = qpnp_ibb_ps_config(labibb, true);
if (rc)
pr_err("Unable to enable IBB PS rc=%d\n", rc);
return rc;
}
@ -2120,47 +2147,16 @@ static int qpnp_ibb_dt_init(struct qpnp_labibb *labibb,
}
if (of_property_read_bool(of_node, "qcom,qpnp-ibb-ps-enable")) {
val = IBB_PS_CTL_EN;
rc = qpnp_labibb_write(labibb, labibb->ibb_base +
REG_IBB_PS_CTL,
&val,
1);
rc = qpnp_ibb_ps_config(labibb, true);
if (rc) {
pr_err("qpnp_ibb_dt_init write register %x failed rc = %d\n",
REG_IBB_PS_CTL, rc);
return rc;
}
val = IBB_NLIMIT_DAC_EN;
rc = qpnp_labibb_write(labibb, labibb->ibb_base +
REG_IBB_NLIMIT_DAC,
&val,
1);
if (rc) {
pr_err("qpnp_ibb_dt_init write register %x failed rc = %d\n",
REG_IBB_NLIMIT_DAC, rc);
pr_err("qpnp_ibb_dt_init PS enable failed rc=%d\n", rc);
return rc;
}
} else {
val = IBB_PS_CTL_DISABLE;
rc = qpnp_labibb_write(labibb, labibb->ibb_base +
REG_IBB_PS_CTL,
&val,
1);
rc = qpnp_ibb_ps_config(labibb, false);
if (rc) {
pr_err("qpnp_ibb_dt_init write register %x failed rc = %d\n",
REG_IBB_PS_CTL, rc);
return rc;
}
val = IBB_NLIMIT_DAC_DISABLE;
rc = qpnp_labibb_write(labibb, labibb->ibb_base +
REG_IBB_NLIMIT_DAC,
&val,
1);
if (rc) {
pr_err("qpnp_ibb_dt_init write register %x failed rc = %d\n",
REG_IBB_NLIMIT_DAC, rc);
pr_err("qpnp_ibb_dt_init PS disable failed rc=%d\n",
rc);
return rc;
}
}
@ -2802,6 +2798,13 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev)
if (rc)
labibb->swire_2nd_cmd_delay =
SWIRE_DEFAULT_2ND_CMD_DLY_MS;
rc = of_property_read_u32(labibb->dev->of_node,
"qcom,swire-ibb-ps-enable-delay",
&labibb->swire_ibb_ps_enable_delay);
if (rc)
labibb->swire_ibb_ps_enable_delay =
SWIRE_DEFAULT_IBB_PS_ENABLE_DLY_MS;
}
if (of_get_available_child_count(pdev->dev.of_node) == 0) {