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:
parent
72ba8906bc
commit
93aea9eb5c
2 changed files with 139 additions and 1 deletions
|
@ -34,6 +34,13 @@ Main node optional properties:
|
||||||
if qpnp,qpnp-labibb-mode = "amoled".
|
if qpnp,qpnp-labibb-mode = "amoled".
|
||||||
- qcom,labibb-ttw-force-lab-on: A boolean property which forces LAB to be
|
- qcom,labibb-ttw-force-lab-on: A boolean property which forces LAB to be
|
||||||
always on during TTW mode.
|
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:
|
LAB subnode required properties:
|
||||||
|
|
||||||
|
@ -203,12 +210,16 @@ Example:
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
qpnp,qpnp-labibb-mode = "lcd";
|
qpnp,qpnp-labibb-mode = "lcd";
|
||||||
qcom,pmic-revid = <&pmi8994_revid>;
|
qcom,pmic-revid = <&pmi8994_revid>;
|
||||||
|
qcom,skip-2nd-swire-cmd;
|
||||||
|
|
||||||
lab_regulator: qcom,lab@de00 {
|
lab_regulator: qcom,lab@de00 {
|
||||||
reg = <0xde00 0x100>;
|
reg = <0xde00 0x100>;
|
||||||
reg-names = "lab";
|
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-min-microvolt = <4600000>;
|
||||||
regulator-max-microvolt = <6000000>;
|
regulator-max-microvolt = <6000000>;
|
||||||
|
|
||||||
|
|
|
@ -15,11 +15,13 @@
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/of_irq.h>
|
||||||
#include <linux/spmi.h>
|
#include <linux/spmi.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
|
@ -247,6 +249,9 @@
|
||||||
#define IBB_DIS_DLY_MASK ((1 << IBB_DIS_DLY_BITS) - 1)
|
#define IBB_DIS_DLY_MASK ((1 << IBB_DIS_DLY_BITS) - 1)
|
||||||
#define IBB_WAIT_MBG_OK BIT(2)
|
#define IBB_WAIT_MBG_OK BIT(2)
|
||||||
|
|
||||||
|
/* Constants */
|
||||||
|
#define SWIRE_DEFAULT_2ND_CMD_DLY_MS 20
|
||||||
|
|
||||||
enum pmic_subtype {
|
enum pmic_subtype {
|
||||||
PMI8994 = 10,
|
PMI8994 = 10,
|
||||||
PMI8950 = 17,
|
PMI8950 = 17,
|
||||||
|
@ -280,6 +285,7 @@ enum ibb_mode {
|
||||||
IBB_SW_CONTROL_EN,
|
IBB_SW_CONTROL_EN,
|
||||||
IBB_SW_CONTROL_DIS,
|
IBB_SW_CONTROL_DIS,
|
||||||
IBB_HW_CONTROL,
|
IBB_HW_CONTROL,
|
||||||
|
IBB_HW_SW_CONTROL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int ibb_discharge_resistor_plan[] = {
|
static const int ibb_discharge_resistor_plan[] = {
|
||||||
|
@ -437,6 +443,7 @@ struct lab_regulator {
|
||||||
struct regulator_dev *rdev;
|
struct regulator_dev *rdev;
|
||||||
struct mutex lab_mutex;
|
struct mutex lab_mutex;
|
||||||
|
|
||||||
|
int lab_vreg_ok_irq;
|
||||||
int curr_volt;
|
int curr_volt;
|
||||||
int min_volt;
|
int min_volt;
|
||||||
|
|
||||||
|
@ -480,6 +487,8 @@ struct qpnp_labibb {
|
||||||
bool ibb_settings_saved;
|
bool ibb_settings_saved;
|
||||||
bool swire_control;
|
bool swire_control;
|
||||||
bool ttw_force_lab_on;
|
bool ttw_force_lab_on;
|
||||||
|
bool skip_2nd_swire_cmd;
|
||||||
|
u32 swire_2nd_cmd_delay;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ibb_settings_index {
|
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;
|
val = IBB_ENABLE_CTL_MODULE_EN;
|
||||||
else if (mode == IBB_HW_CONTROL)
|
else if (mode == IBB_HW_CONTROL)
|
||||||
val = IBB_ENABLE_CTL_SWIRE_RDY;
|
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)
|
else if (mode == IBB_SW_CONTROL_DIS)
|
||||||
val = 0;
|
val = 0;
|
||||||
else
|
else
|
||||||
|
@ -1556,6 +1567,77 @@ static int qpnp_lab_regulator_set_voltage(struct regulator_dev *rdev,
|
||||||
return 0;
|
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, ®,
|
||||||
|
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)
|
static int qpnp_lab_regulator_get_voltage(struct regulator_dev *rdev)
|
||||||
{
|
{
|
||||||
struct qpnp_labibb *labibb = rdev_get_drvdata(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,
|
rc = qpnp_labibb_read(labibb, &val,
|
||||||
labibb->ibb_base + REG_IBB_ENABLE_CTL, 1);
|
labibb->ibb_base + REG_IBB_ENABLE_CTL, 1);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
@ -2520,6 +2615,21 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb,
|
||||||
return 0;
|
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)
|
static int qpnp_labibb_check_ttw_supported(struct qpnp_labibb *labibb)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
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");
|
pr_err("Invalid mode for SWIRE control\n");
|
||||||
return -EINVAL;
|
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) {
|
if (of_get_available_child_count(pdev->dev.of_node) == 0) {
|
||||||
pr_err("no child nodes\n");
|
pr_err("no child nodes\n");
|
||||||
|
@ -2653,6 +2774,12 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev)
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case QPNP_LAB_TYPE:
|
case QPNP_LAB_TYPE:
|
||||||
labibb->lab_base = base;
|
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);
|
rc = register_qpnp_lab_regulator(labibb, child);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto fail_registration;
|
goto fail_registration;
|
||||||
|
|
Loading…
Add table
Reference in a new issue