regulator: qpnp-amoled: add support to disable pulse skipping

On some customer display panels, touch ghosting can happen due to
a voltage ripple from amoled. Add support to fix this issue, following
HW recommendation, by disabling smart pulse skipping in module
probe and disabling forced PSM when AMOLED is enabled.

Change-Id: Id5886d4cdaf2aa58bc53a874041bfae90374fafb
Signed-off-by: Jishnu Prakash <jprakash@codeaurora.org>
This commit is contained in:
Jishnu Prakash 2020-11-18 16:55:33 +05:30
parent 6151ff0c6a
commit 2749076bc9

View File

@ -29,11 +29,26 @@
#define PULLDN_EN_BIT BIT(7)
/* IBB */
#define IBB_STATUS_2(chip) (chip->ibb_base + 0x09)
#define SOFT_START_DONE_BIT BIT(6)
#define IBB_STATUS_5(chip) (chip->ibb_base + 0x0c)
#define SWIRE_STATUS_BIT BIT(0)
#define IBB_PD_CTL(chip) (chip->ibb_base + 0x47)
/* IBB_PD_CTL */
#define ENABLE_PD_BIT BIT(7)
/* IBB_PS_CTL */
#define IBB_PS_CTL(chip) (chip->ibb_base + 0x50)
#define EN_PS_BIT BIT(7)
#define PS_THRESHOLD_0P5 0x1
#define IBB_SMART_PS_CTL(chip) (chip->ibb_base + 0x65)
#define STARTUP_PS_BIT BIT(5)
#define STEADY_STATE_PS_BIT BIT(4)
#define IBB_DUAL_PHASE_CTL(chip) (chip->ibb_base + 0x70)
/* IBB_DUAL_PHASE_CTL */
@ -73,6 +88,7 @@ struct ibb_regulator {
bool swire_control;
bool pd_control;
bool single_phase;
bool force_ccm_mode;
};
struct qpnp_amoled {
@ -86,6 +102,8 @@ struct qpnp_amoled {
u32 oledb_base;
u32 ab_base;
u32 ibb_base;
struct work_struct ibb_ccm_wa_work;
};
enum reg_type {
@ -183,6 +201,12 @@ static int qpnp_ibb_regulator_enable(struct regulator_dev *rdev)
struct qpnp_amoled *chip = rdev_get_drvdata(rdev);
chip->ibb.vreg.enabled = true;
if (chip->ibb.force_ccm_mode) {
cancel_work_sync(&chip->ibb_ccm_wa_work);
pm_stay_awake(chip->dev);
schedule_work(&chip->ibb_ccm_wa_work);
}
return 0;
}
@ -191,6 +215,12 @@ static int qpnp_ibb_regulator_disable(struct regulator_dev *rdev)
struct qpnp_amoled *chip = rdev_get_drvdata(rdev);
chip->ibb.vreg.enabled = false;
if (chip->ibb.force_ccm_mode) {
cancel_work_sync(&chip->ibb_ccm_wa_work);
pm_stay_awake(chip->dev);
schedule_work(&chip->ibb_ccm_wa_work);
}
return 0;
}
@ -493,6 +523,56 @@ static int qpnp_amoled_regulator_register(struct qpnp_amoled *chip,
return rc;
}
#define IBB_RETRY_COUNT 25
#define IBB_POLL_DELAY_MS 20
static void qpnp_amoled_toggle_ps_ctl(struct work_struct *work)
{
struct qpnp_amoled *chip = container_of(work,
struct qpnp_amoled, ibb_ccm_wa_work);
int i, rc;
u8 val;
if (chip->ibb.vreg.enabled) {
for (i = 0; i < IBB_RETRY_COUNT; i++) {
rc = qpnp_amoled_read(chip, IBB_STATUS_2(chip), &val, 1);
if (rc < 0)
goto out;
if (val & SOFT_START_DONE_BIT) {
val = PS_THRESHOLD_0P5;
rc = qpnp_amoled_write(chip, IBB_PS_CTL(chip), &val, 1);
if (rc < 0)
pr_err("Failed to disable forced-PSM, rc = %d\n", rc);
goto out;
}
msleep(IBB_POLL_DELAY_MS);
}
pr_err("Timeout - failed to disable forced-PSM, IBB_STATUS_2:0x%x\n",
val);
} else {
for (i = 0; i < IBB_RETRY_COUNT; i++) {
rc = qpnp_amoled_read(chip, IBB_STATUS_5(chip), &val, 1);
if (rc < 0)
goto out;
if (!(val & SWIRE_STATUS_BIT)) {
val = EN_PS_BIT | PS_THRESHOLD_0P5;
rc = qpnp_amoled_write(chip, IBB_PS_CTL(chip), &val, 1);
if (rc < 0)
pr_err("Failed to enable forced-PSM, rc = %d\n", rc);
goto out;
}
msleep(IBB_POLL_DELAY_MS);
}
pr_err("Timeout - failed to enable forced-PSM, IBB_STATUS_5:0x%x\n",
val);
}
out:
pm_relax(chip->dev);
}
static int qpnp_amoled_hw_init(struct qpnp_amoled *chip)
{
int rc;
@ -528,6 +608,15 @@ static int qpnp_amoled_hw_init(struct qpnp_amoled *chip)
return rc;
}
if (chip->ibb.force_ccm_mode) {
val = STARTUP_PS_BIT | STEADY_STATE_PS_BIT;
rc = qpnp_amoled_write(chip, IBB_SMART_PS_CTL(chip), &val, 1);
if (rc < 0)
return rc;
INIT_WORK(&chip->ibb_ccm_wa_work, qpnp_amoled_toggle_ps_ctl);
}
return 0;
}
@ -578,6 +667,8 @@ static int qpnp_amoled_parse_dt(struct qpnp_amoled *chip)
"qcom,aod-pd-control");
chip->ibb.single_phase = of_property_read_bool(temp,
"qcom,ibb-single-phase");
chip->ibb.force_ccm_mode = of_property_read_bool(temp,
"qcom,ibb-enable-force-ccm-wa");
break;
default:
pr_err("Unknown peripheral type 0x%x\n", val[0]);
@ -625,12 +716,21 @@ static int qpnp_amoled_regulator_probe(struct platform_device *pdev)
if (rc < 0)
dev_err(chip->dev, "Failed to initialize HW rc=%d\n", rc);
device_init_wakeup(chip->dev, true);
error:
return rc;
}
static int qpnp_amoled_regulator_remove(struct platform_device *pdev)
{
struct qpnp_amoled *chip = dev_get_drvdata(&pdev->dev);
if (chip->ibb.force_ccm_mode)
cancel_work_sync(&chip->ibb_ccm_wa_work);
device_init_wakeup(chip->dev, false);
return 0;
}