regulator: qpnp-labibb: Add logic to skip second SWIRE command

On newer AMOLED panels the second SWIRE command is expected to
control the AVDD voltage. However, the PMI8950/PMI8994 IBB module
interprets this command for VDISN and incorrectly reduces its voltage.

Add DT properties 'qcom,skip-2nd-swire-cmd' to skip the second
SWIRE command and 'qcom,swire-2nd-cmd-delay' to explicitly specify
the delay between the first and second SWIRE command.

CRs-Fixed: 938038
Change-Id: I617a8490784efd760651b3ec8780cc4fd4b17bae
Signed-off-by: Anirudh Ghayal <aghayal@codeaurora.org>
Signed-off-by: Subbaraman Narayanamurthy <subbaram@codeaurora.org>
This commit is contained in:
Anirudh Ghayal 2016-03-01 16:28:56 +05:30 committed by Jeevan Shriram
parent 72ba8906bc
commit 93aea9eb5c
2 changed files with 139 additions and 1 deletions

View file

@ -34,6 +34,13 @@ Main node optional properties:
if qpnp,qpnp-labibb-mode = "amoled".
- qcom,labibb-ttw-force-lab-on: A boolean property which forces LAB to be
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
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.
LAB subnode required properties:
@ -203,12 +210,16 @@ Example:
#size-cells = <1>;
qpnp,qpnp-labibb-mode = "lcd";
qcom,pmic-revid = <&pmi8994_revid>;
qcom,skip-2nd-swire-cmd;
lab_regulator: qcom,lab@de00 {
reg = <0xde00 0x100>;
reg-names = "lab";
regulator-name = "lab_reg";
interrupts = <0x3 0xde 0x0>;
interrupt-names = "lab-vreg-ok";
regulator-name = "lab_reg";
regulator-min-microvolt = <4600000>;
regulator-max-microvolt = <6000000>;

View file

@ -15,11 +15,13 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/regmap.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/spmi.h>
#include <linux/platform_device.h>
#include <linux/string.h>
@ -247,6 +249,9 @@
#define IBB_DIS_DLY_MASK ((1 << IBB_DIS_DLY_BITS) - 1)
#define IBB_WAIT_MBG_OK BIT(2)
/* Constants */
#define SWIRE_DEFAULT_2ND_CMD_DLY_MS 20
enum pmic_subtype {
PMI8994 = 10,
PMI8950 = 17,
@ -280,6 +285,7 @@ enum ibb_mode {
IBB_SW_CONTROL_EN,
IBB_SW_CONTROL_DIS,
IBB_HW_CONTROL,
IBB_HW_SW_CONTROL,
};
static const int ibb_discharge_resistor_plan[] = {
@ -437,6 +443,7 @@ struct lab_regulator {
struct regulator_dev *rdev;
struct mutex lab_mutex;
int lab_vreg_ok_irq;
int curr_volt;
int min_volt;
@ -480,6 +487,8 @@ struct qpnp_labibb {
bool ibb_settings_saved;
bool swire_control;
bool ttw_force_lab_on;
bool skip_2nd_swire_cmd;
u32 swire_2nd_cmd_delay;
};
enum ibb_settings_index {
@ -654,6 +663,8 @@ static int qpnp_ibb_set_mode(struct qpnp_labibb *labibb, enum ibb_mode mode)
val = IBB_ENABLE_CTL_MODULE_EN;
else if (mode == IBB_HW_CONTROL)
val = IBB_ENABLE_CTL_SWIRE_RDY;
else if (mode == IBB_HW_SW_CONTROL)
val = IBB_ENABLE_CTL_MODULE_EN | IBB_ENABLE_CTL_SWIRE_RDY;
else if (mode == IBB_SW_CONTROL_DIS)
val = 0;
else
@ -1556,6 +1567,77 @@ static int qpnp_lab_regulator_set_voltage(struct regulator_dev *rdev,
return 0;
}
static int qpnp_skip_swire_command(struct qpnp_labibb *labibb)
{
int rc = 0, retry = 50, dly;
u8 reg;
do {
/* poll for ibb vreg_ok */
rc = qpnp_labibb_read(labibb, &reg,
labibb->ibb_base + REG_IBB_STATUS1, 1);
if (rc) {
pr_err("Failed to read ibb_status1 reg rc=%d\n", rc);
return rc;
}
if ((reg & IBB_STATUS1_VREG_OK_MASK) == IBB_STATUS1_VREG_OK)
break;
/* poll delay */
usleep_range(500, 600);
} while (--retry);
if (!retry) {
pr_err("ibb vreg_ok failed to turn-on\n");
return -EBUSY;
}
/* move to SW control */
rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_EN);
if (rc) {
pr_err("Failed switch to IBB_SW_CONTROL rc=%d\n", rc);
return rc;
}
/* delay to skip the second swire command */
dly = labibb->swire_2nd_cmd_delay * 1000;
while (dly / 20000) {
usleep_range(20000, 20010);
dly -= 20000;
}
if (dly)
usleep_range(dly, dly + 10);
rc = qpnp_ibb_set_mode(labibb, IBB_HW_SW_CONTROL);
if (rc) {
pr_err("Failed switch to IBB_HW_SW_CONTROL rc=%d\n", rc);
return rc;
}
/* delay for SPMI to SWIRE transition */
usleep_range(1000, 1100);
/* Move back to SWIRE control */
rc = qpnp_ibb_set_mode(labibb, IBB_HW_CONTROL);
if (rc)
pr_err("Failed switch to IBB_HW_CONTROL rc=%d\n", rc);
return rc;
}
static irqreturn_t lab_vreg_ok_handler(int irq, void *_labibb)
{
struct qpnp_labibb *labibb = _labibb;
int rc;
rc = qpnp_skip_swire_command(labibb);
if (rc)
pr_err("Failed in 'qpnp_skip_swire_command' rc=%d\n", rc);
return IRQ_HANDLED;
}
static int qpnp_lab_regulator_get_voltage(struct regulator_dev *rdev)
{
struct qpnp_labibb *labibb = rdev_get_drvdata(rdev);
@ -1707,6 +1789,19 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb,
}
}
if (labibb->skip_2nd_swire_cmd) {
rc = devm_request_threaded_irq(labibb->dev,
labibb->lab_vreg.lab_vreg_ok_irq, NULL,
lab_vreg_ok_handler,
IRQF_ONESHOT | IRQF_TRIGGER_RISING,
"lab-vreg-ok", labibb);
if (rc) {
pr_err("Failed to register 'lab-vreg-ok' irq rc=%d\n",
rc);
return rc;
}
}
rc = qpnp_labibb_read(labibb, &val,
labibb->ibb_base + REG_IBB_ENABLE_CTL, 1);
if (rc) {
@ -2520,6 +2615,21 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb,
return 0;
}
static int qpnp_lab_register_irq(struct device_node *child,
struct qpnp_labibb *labibb)
{
if (labibb->skip_2nd_swire_cmd) {
labibb->lab_vreg.lab_vreg_ok_irq =
of_irq_get_byname(child, "lab-vreg-ok");
if (labibb->lab_vreg.lab_vreg_ok_irq < 0) {
pr_err("Invalid lab-vreg-ok irq\n");
return -EINVAL;
}
}
return 0;
}
static int qpnp_labibb_check_ttw_supported(struct qpnp_labibb *labibb)
{
int rc = 0;
@ -2629,6 +2739,17 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev)
pr_err("Invalid mode for SWIRE control\n");
return -EINVAL;
}
if (labibb->swire_control) {
labibb->skip_2nd_swire_cmd =
of_property_read_bool(labibb->dev->of_node,
"qcom,skip-2nd-swire-cmd");
rc = of_property_read_u32(labibb->dev->of_node,
"qcom,swire-2nd-cmd-delay",
&labibb->swire_2nd_cmd_delay);
if (rc)
labibb->swire_2nd_cmd_delay =
SWIRE_DEFAULT_2ND_CMD_DLY_MS;
}
if (of_get_available_child_count(pdev->dev.of_node) == 0) {
pr_err("no child nodes\n");
@ -2653,6 +2774,12 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev)
switch (type) {
case QPNP_LAB_TYPE:
labibb->lab_base = base;
rc = qpnp_lab_register_irq(child, labibb);
if (rc) {
pr_err("Failed to register LAB IRQ rc=%d\n",
rc);
goto fail_registration;
}
rc = register_qpnp_lab_regulator(labibb, child);
if (rc)
goto fail_registration;