summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVishnuvardhan Prodduturi <vproddut@codeaurora.org>2015-10-20 21:14:27 +0530
committerDhaval Patel <pdhaval@codeaurora.org>2016-05-03 17:16:58 -0700
commitb5bf55e32d4836c1704f78af06f5bd8d78a3be6a (patch)
treeca2d9cdf1148c1c8678725bb7b01b9c646a1df74
parent689e0e1f51b3dcea770408c180246799ec6948c6 (diff)
qpnp: wled: update PMI settings for AMOLED Panel.
Update the LAB/IBB/WLED_CTRL settings for AMOLED display type as per the recommendations from the systems team. This helps to avoid flickers on the display panel. Change-Id: Ic598676a6b8bb23e81e1800fe6c5e5976f459cc7
-rw-r--r--dev/qpnp_wled/include/qpnp_wled.h14
-rw-r--r--dev/qpnp_wled/qpnp_wled.c153
2 files changed, 120 insertions, 47 deletions
diff --git a/dev/qpnp_wled/include/qpnp_wled.h b/dev/qpnp_wled/include/qpnp_wled.h
index dcd4a8a8..3f037031 100644
--- a/dev/qpnp_wled/include/qpnp_wled.h
+++ b/dev/qpnp_wled/include/qpnp_wled.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -44,6 +44,10 @@
#define QPNP_WLED_SWITCH_FREQ_REG(b) (b + 0x4C)
#define QPNP_WLED_OVP_REG(b) (b + 0x4D)
#define QPNP_WLED_ILIM_REG(b) (b + 0x4E)
+#define QPNP_WLED_VLOOP_COMP_RES(b) (b + 0x55)
+#define QPNP_WLED_VLOOP_COMP_GM(b) (b + 0x56)
+#define QPNP_WLED_PSM_CTRL(b) (b + 0x5B)
+#define QPNP_WLED_TEST4(b) (b + 0xE5)
#define QPNP_WLED_EN_MASK 0x7F
#define QPNP_WLED_EN_SHIFT 7
@@ -134,6 +138,9 @@
#define QPNP_WLED_MODULE_RDY_SHIFT 7
#define QPNP_WLED_MODULE_EN_MASK 0x7F
#define QPNP_WLED_MODULE_EN_SHIFT 7
+#define QPNP_IBB_SWIRE_RDY_MASK 0x40
+#define QPNP_IBB_SWIRE_RDY_SHIFT 6
+#define QPNP_IBB_MODULE_EN_MASK 0x80
#define QPNP_WLED_DISP_SEL_MASK 0x7F
#define QPNP_WLED_DISP_SEL_SHIFT 7
@@ -148,6 +155,7 @@
#define QPNP_WLED_IBB_PWRDN_DLY_MAX_MS 3
#define IBB_LAB_VREG_STEP_SIZE 100000
#define QPNP_LABIBB_OUTPUT_VOLTAGE 0x41
+#define QPNP_LABIBB_PS_CTL 0x50
#define QPNP_LAB_OUTPUT_OVERRIDE_EN BIT(7)
#define QPNP_LAB_SET_VOLTAGE_MASK (BIT(4) - 1)
#define QPNP_IBB_SET_VOLTAGE_MASK (BIT(6) - 1)
@@ -260,6 +268,8 @@ struct qpnp_wled {
uint32_t ibb_max_volt;
uint32_t ibb_init_volt;
uint32_t lab_init_volt;
+ bool lab_ibb_swire_control;
+ bool wled_avdd_control;
};
struct qpnp_wled_config_data {
@@ -273,6 +283,8 @@ struct qpnp_wled_config_data {
uint32_t ibb_max_volt;
uint32_t ibb_init_volt;
uint32_t lab_init_volt;
+ bool lab_ibb_swire_control;
+ bool wled_avdd_control;
};
/* WLED Initial Setup */
int qpnp_wled_init(struct qpnp_wled_config_data *config);
diff --git a/dev/qpnp_wled/qpnp_wled.c b/dev/qpnp_wled/qpnp_wled.c
index 0ae44a3c..9cedbb7e 100644
--- a/dev/qpnp_wled/qpnp_wled.c
+++ b/dev/qpnp_wled/qpnp_wled.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.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -95,6 +95,21 @@ static int qpnp_wled_enable(struct qpnp_wled *wled,
return 0;
}
+static int qpnp_wled_ibb_swire_rdy(struct qpnp_wled *wled,
+ uint16_t base_addr, bool state)
+{
+ uint8_t reg;
+
+ reg = pm8x41_wled_reg_read(
+ QPNP_WLED_MODULE_EN_REG(base_addr));
+ /* Do not enable IBB module when SWIRE ready is set */
+ reg &= ~(QPNP_IBB_SWIRE_RDY_MASK | QPNP_IBB_MODULE_EN_MASK);
+ reg |= (state << QPNP_IBB_SWIRE_RDY_SHIFT);
+ pm8x41_wled_reg_write(QPNP_WLED_MODULE_EN_REG(base_addr), reg);
+
+ return 0;
+}
+
int qpnp_ibb_enable(bool state)
{
int rc = 0;
@@ -119,7 +134,10 @@ int qpnp_ibb_enable(bool state)
pm8x41_wled_reg_write(QPNP_WLED_LAB_IBB_RDY_REG(gwled->lab_base), reg);
}
- rc = qpnp_wled_enable(gwled, gwled->ibb_base, state);
+ if (gwled->disp_type_amoled && gwled->lab_ibb_swire_control)
+ rc = qpnp_wled_ibb_swire_rdy(gwled, gwled->ibb_base, state);
+ else
+ rc = qpnp_wled_enable(gwled, gwled->ibb_base, state);
return rc;
}
@@ -141,12 +159,14 @@ void qpnp_wled_enable_backlight(int enable)
return;
}
}
- rc = qpnp_wled_enable(gwled, gwled->ctrl_base, enable);
- if (rc) {
- dprintf(CRITICAL,"wled %sable failed\n",
- enable ? "en" : "dis");
- return;
+ if (!gwled->disp_type_amoled || !gwled->wled_avdd_control) {
+ rc = qpnp_wled_enable(gwled, gwled->ctrl_base, enable);
+ if (rc) {
+ dprintf(CRITICAL, "wled %sable failed\n",
+ enable ? "en" : "dis");
+ return;
+ }
}
}
@@ -195,6 +215,21 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
if (rc < 0)
return rc;
+ /* Recommended WLED MDOS settings for AMOLED */
+ if (wled->disp_type_amoled) {
+ pm8x41_wled_reg_write(QPNP_WLED_VLOOP_COMP_RES(wled->ctrl_base),
+ 0x8F);
+ pm8x41_wled_reg_write(QPNP_WLED_VLOOP_COMP_GM(wled->ctrl_base),
+ 0x81);
+ pm8x41_wled_reg_write(QPNP_WLED_PSM_CTRL(wled->ctrl_base),
+ 0x83);
+
+ rc = qpnp_wled_sec_access(wled, wled->ctrl_base);
+ if (rc)
+ return rc;
+ pm8x41_wled_reg_write(QPNP_WLED_TEST4(wled->ctrl_base), 0x13);
+ }
+
/* Configure the FEEDBACK OUTPUT register */
reg = pm8x41_wled_reg_read(
QPNP_WLED_FDBK_OP_REG(wled->ctrl_base));
@@ -402,6 +437,11 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
if (rc < 0)
return rc;
+ /* Disable LAB pulse skipping for AMOLED */
+ if (wled->disp_type_amoled)
+ pm8x41_wled_reg_write(wled->lab_base +
+ QPNP_LABIBB_PS_CTL, 0x00);
+
/* IBB active bias */
if (wled->ibb_pwrup_dly_ms > QPNP_WLED_IBB_PWRUP_DLY_MAX_MS)
wled->ibb_pwrup_dly_ms = QPNP_WLED_IBB_PWRUP_DLY_MAX_MS;
@@ -493,6 +533,8 @@ static int qpnp_wled_setup(struct qpnp_wled *wled, struct qpnp_wled_config_data
wled->ibb_max_volt = config->ibb_max_volt;
wled->ibb_init_volt = config->ibb_init_volt;
wled->lab_init_volt = config->lab_init_volt;
+ wled->lab_ibb_swire_control = config->lab_ibb_swire_control;
+ wled->wled_avdd_control = config->wled_avdd_control;
return 0;
}
@@ -531,49 +573,68 @@ static int qpnp_labibb_regulator_set_voltage(struct qpnp_wled *wled)
uint32_t new_uV;
uint8_t val, mask=0;
- if (wled->lab_min_volt < wled->lab_init_volt) {
- dprintf(CRITICAL,"qpnp_lab_regulator_set_voltage failed, min_uV %d is less than init volt %d\n",
- wled->lab_min_volt, wled->lab_init_volt);
- return rc;
- }
+ if (!wled->disp_type_amoled || !wled->lab_ibb_swire_control) {
+ if (wled->lab_min_volt < wled->lab_init_volt) {
+ dprintf(CRITICAL,"qpnp_lab_regulator_set_voltage failed, min_uV %d is less than init volt %d\n",
+ wled->lab_min_volt, wled->lab_init_volt);
+ return rc;
+ }
- val = (((wled->lab_min_volt - wled->lab_init_volt) + (IBB_LAB_VREG_STEP_SIZE - 1)) / IBB_LAB_VREG_STEP_SIZE);
- new_uV = val * IBB_LAB_VREG_STEP_SIZE + wled->lab_init_volt;
+ val = (((wled->lab_min_volt - wled->lab_init_volt) +
+ (IBB_LAB_VREG_STEP_SIZE - 1)) / IBB_LAB_VREG_STEP_SIZE);
+ new_uV = val * IBB_LAB_VREG_STEP_SIZE + wled->lab_init_volt;
- if (new_uV > wled->lab_max_volt) {
- dprintf(CRITICAL,"qpnp_ibb_regulator_set_voltage unable to set voltage (%d %d)\n",
- wled->lab_min_volt, wled->lab_max_volt);
- return rc;
- }
- val |= QPNP_LAB_OUTPUT_OVERRIDE_EN;
- mask = pm8x41_wled_reg_read(wled->lab_base + QPNP_LABIBB_OUTPUT_VOLTAGE);
- mask &= ~(QPNP_LAB_SET_VOLTAGE_MASK | QPNP_LAB_OUTPUT_OVERRIDE_EN);
- mask |= val & (QPNP_LAB_SET_VOLTAGE_MASK | QPNP_LAB_OUTPUT_OVERRIDE_EN);
-
- pm8x41_wled_reg_write(wled->lab_base + QPNP_LABIBB_OUTPUT_VOLTAGE, mask);
- udelay(2);
-
- /* IBB Set Voltage */
- if (wled->ibb_min_volt < wled->ibb_init_volt) {
- dprintf(CRITICAL, "qpnp_ibb_regulator_set_voltage failed, min_uV %d is less than init volt %d\n",
- wled->ibb_min_volt, wled->ibb_init_volt);
- return rc;
- }
+ if (new_uV > wled->lab_max_volt) {
+ dprintf(CRITICAL,"qpnp_ibb_regulator_set_voltage unable to set voltage (%d %d)\n",
+ wled->lab_min_volt, wled->lab_max_volt);
+ return rc;
+ }
+ val |= QPNP_LAB_OUTPUT_OVERRIDE_EN;
+ mask = pm8x41_wled_reg_read(wled->lab_base +
+ QPNP_LABIBB_OUTPUT_VOLTAGE);
+ mask &= ~(QPNP_LAB_SET_VOLTAGE_MASK
+ | QPNP_LAB_OUTPUT_OVERRIDE_EN);
+ mask |= val & (QPNP_LAB_SET_VOLTAGE_MASK
+ | QPNP_LAB_OUTPUT_OVERRIDE_EN);
+
+ pm8x41_wled_reg_write(wled->lab_base +
+ QPNP_LABIBB_OUTPUT_VOLTAGE, mask);
+ udelay(2);
+
+ /*
+ * IBB Set Voltage.
+ * For AMOLED panels, the IBB voltage needs to be
+ * controlled by panel.
+ */
+ if (wled->ibb_min_volt < wled->ibb_init_volt) {
+ dprintf(CRITICAL, "qpnp_ibb_regulator_set_voltage failed, min_uV %d is less than init volt %d\n",
+ wled->ibb_min_volt, wled->ibb_init_volt);
+ return rc;
+ }
- val = (((wled->ibb_min_volt - wled->ibb_init_volt) + (IBB_LAB_VREG_STEP_SIZE - 1)) / IBB_LAB_VREG_STEP_SIZE);
- new_uV = val * IBB_LAB_VREG_STEP_SIZE + wled->ibb_init_volt;
- if (new_uV > wled->ibb_max_volt) {
- dprintf(CRITICAL,"qpnp_ibb_regulator_set_voltage unable to set voltage %d %d\n",
- wled->ibb_min_volt, wled->ibb_max_volt);
- return rc;
+ val = (((wled->ibb_min_volt - wled->ibb_init_volt) +
+ (IBB_LAB_VREG_STEP_SIZE - 1)) / IBB_LAB_VREG_STEP_SIZE);
+ new_uV = val * IBB_LAB_VREG_STEP_SIZE + wled->ibb_init_volt;
+ if (new_uV > wled->ibb_max_volt) {
+ dprintf(CRITICAL, "qpnp_ibb_regulator_set_voltage unable to set voltage %d %d\n",
+ wled->ibb_min_volt, wled->ibb_max_volt);
+ return rc;
+ }
+ val |= QPNP_LAB_OUTPUT_OVERRIDE_EN;
+ mask = pm8x41_wled_reg_read(wled->ibb_base +
+ QPNP_LABIBB_OUTPUT_VOLTAGE);
+ udelay(2);
+ mask &= ~(QPNP_IBB_SET_VOLTAGE_MASK |
+ QPNP_LAB_OUTPUT_OVERRIDE_EN);
+ mask |= (val & (QPNP_IBB_SET_VOLTAGE_MASK |
+ QPNP_LAB_OUTPUT_OVERRIDE_EN));
+
+ pm8x41_wled_reg_write(wled->ibb_base +
+ QPNP_LABIBB_OUTPUT_VOLTAGE, mask);
+ } else {
+ pm8x41_wled_reg_write(wled->ibb_base +
+ QPNP_LABIBB_OUTPUT_VOLTAGE, 0x00);
}
- val |= QPNP_LAB_OUTPUT_OVERRIDE_EN;
- mask = pm8x41_wled_reg_read(wled->ibb_base + QPNP_LABIBB_OUTPUT_VOLTAGE);
- udelay(2);
- mask &= ~(QPNP_IBB_SET_VOLTAGE_MASK | QPNP_LAB_OUTPUT_OVERRIDE_EN);
- mask |= (val & (QPNP_IBB_SET_VOLTAGE_MASK | QPNP_LAB_OUTPUT_OVERRIDE_EN));
-
- pm8x41_wled_reg_write(wled->ibb_base + QPNP_LABIBB_OUTPUT_VOLTAGE,mask);
return 0;
}