From 543dc23bf7dbf0a3fa942bcdcecb8602328fbbb1 Mon Sep 17 00:00:00 2001 From: Adrian Salido Date: Thu, 11 Jul 2019 17:18:46 -0700 Subject: [PATCH] regulator: qpnp-amoled: remove AB ldo bypass The AB LDO bypass could lead to a race condition during AOD->Normal transition, that could lead to PMIC issue. Disable the bypass to avoid this. Bug: 137055672 Change-Id: I1d94379b51095740635ea7be034cbb826411e0f7 Signed-off-by: Adrian Salido --- .../regulator/qpnp-amoled-regulator.txt | 9 - drivers/regulator/qpnp-amoled-regulator.c | 247 ++---------------- 2 files changed, 22 insertions(+), 234 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/qpnp-amoled-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-amoled-regulator.txt index a6c1ba6f60eb..b3a90f391026 100644 --- a/Documentation/devicetree/bindings/regulator/qpnp-amoled-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qpnp-amoled-regulator.txt @@ -67,15 +67,6 @@ Subnode common properties for OLEDB and AB/IBB regulator devices. Definition: A boolean property to specify that the pull down control for AB/IBB needs to be configured during AOD mode. -Subnode properties for AB regulator device. - -- qcom,aod-entry-poll-time-ms: - Usage: optional - Value type: - Definition: Poll timeout (in ms) for AB VREG_OK to go low during AOD - entry. If this is not specified, a default value of 100 ms - is used. - Subnode properties for OLEDB regulator device. - qcom,default-vout-override: diff --git a/drivers/regulator/qpnp-amoled-regulator.c b/drivers/regulator/qpnp-amoled-regulator.c index c01c67381b3c..e754c26d87bf 100644 --- a/drivers/regulator/qpnp-amoled-regulator.c +++ b/drivers/regulator/qpnp-amoled-regulator.c @@ -79,7 +79,6 @@ struct ab_regulator { /* DT params */ bool swire_control; bool pd_control; - u32 aod_entry_poll_time_ms; }; struct ibb_regulator { @@ -97,7 +96,6 @@ struct qpnp_amoled { struct ab_regulator ab; struct ibb_regulator ibb; struct mutex reg_lock; - struct work_struct aod_work; struct delayed_work vout_work; struct workqueue_struct *wq; @@ -232,102 +230,6 @@ static int qpnp_ab_pd_control(struct qpnp_amoled *chip, bool en) return qpnp_amoled_write(chip, AB_LDO_PD_CTL(chip), &val, 1); } -#define AB_VREG_OK_POLL_TIME_US 2000 -#define AB_VREG_OK_POLL_HIGH_TRIES 8 -#define AB_VREG_OK_POLL_HIGH_TIME_US 10000 -#define AB_VREG_OK_POLL_AGAIN_TRIES 10 - -static int qpnp_ab_poll_vreg_ok(struct qpnp_amoled *chip, bool status, - u32 poll_time_us) -{ - u32 i, poll_us = AB_VREG_OK_POLL_TIME_US, wait_time_us = 0; - bool swire_high = false, poll_again = false, monitor = false; - int rc; - u8 val; - - if (poll_time_us < AB_VREG_OK_POLL_TIME_US) - return -EINVAL; - - i = poll_time_us / AB_VREG_OK_POLL_TIME_US; -loop: - while (i--) { - /* Write a dummy value before reading AB_STATUS1 */ - rc = qpnp_amoled_write(chip, AB_STATUS1(chip), &val, 1); - if (rc < 0) - return rc; - - rc = qpnp_amoled_read(chip, AB_STATUS1(chip), &val, 1); - if (rc < 0) - return rc; - - wait_time_us += poll_us; - if (((val & VREG_OK_BIT) >> VREG_OK_SHIFT) == status) { - pr_debug("Waited for %d us\n", wait_time_us); - - /* - * Return if we're polling for VREG_OK low. Else, poll - * for VREG_OK high for at least 80 ms. IF VREG_OK stays - * high, then consider it as a valid SWIRE pulse. - */ - - if (status) { - swire_high = true; - if (!poll_again && !monitor) { - pr_debug("SWIRE is high, start monitoring\n"); - i = AB_VREG_OK_POLL_HIGH_TRIES; - poll_us = AB_VREG_OK_POLL_HIGH_TIME_US; - wait_time_us = 0; - monitor = true; - } - - if (poll_again) - poll_again = false; - } else { - return 0; - } - } else { - /* - * If we're here when polling for VREG_OK high, then it - * is possibly because of an intermittent SWIRE pulse. - * Ignore it and poll for valid SWIRE pulse again. - */ - if (status && swire_high && monitor) { - pr_debug("SWIRE is low\n"); - poll_again = true; - swire_high = false; - break; - } - - if (poll_again) - poll_again = false; - } - - usleep_range(poll_us, poll_us + 1); - } - - /* - * If poll_again is set, then VREG_OK should be polled for another - * 100 ms for valid SWIRE signal. - */ - - if (poll_again) { - pr_debug("polling again for SWIRE\n"); - i = AB_VREG_OK_POLL_AGAIN_TRIES; - poll_us = AB_VREG_OK_POLL_HIGH_TIME_US; - wait_time_us = 0; - goto loop; - } - - /* If swire_high is set, then it's a valid SWIRE signal, return 0. */ - if (swire_high) { - pr_debug("SWIRE is high\n"); - return 0; - } - - pr_err("AB_STATUS1: %x poll for VREG_OK %d timed out\n", val, status); - return -ETIMEDOUT; -} - static int qpnp_ibb_pd_control(struct qpnp_amoled *chip, bool en) { u8 val = en ? ENABLE_PD_BIT : 0; @@ -336,126 +238,21 @@ static int qpnp_ibb_pd_control(struct qpnp_amoled *chip, bool en) val); } -static int qpnp_ibb_aod_config(struct qpnp_amoled *chip, bool aod) -{ - int rc; - u8 ps_ctl, smart_ps_ctl, nlimit_dac; - - pr_debug("aod: %d\n", aod); - if (aod) { - ps_ctl = 0x82; - smart_ps_ctl = 0; - nlimit_dac = 0; - } else { - ps_ctl = 0x02; - smart_ps_ctl = 0x80; - nlimit_dac = 0x3; - } - - rc = qpnp_amoled_write(chip, IBB_SMART_PS_CTL(chip), &smart_ps_ctl, 1); - if (rc < 0) - return rc; - - rc = qpnp_amoled_write(chip, IBB_NLIMIT_DAC(chip), &nlimit_dac, 1); - if (rc < 0) - return rc; - - rc = qpnp_amoled_write(chip, IBB_PS_CTL(chip), &ps_ctl, 1); - return rc; -} - -static void qpnp_amoled_aod_work(struct work_struct *work) +static int qpnp_amoled_pd_control(struct qpnp_amoled *chip, bool en) { - struct qpnp_amoled *chip = container_of(work, struct qpnp_amoled, - aod_work); - u8 val = 0; - unsigned int mode; - u32 poll_time_us = 100000; - int rc; - - mutex_lock(&chip->reg_lock); - mode = chip->ab.vreg.mode; - mutex_unlock(&chip->reg_lock); - - pr_debug("mode: %d\n", mode); - if (mode == REGULATOR_MODE_NORMAL) { - rc = qpnp_ibb_aod_config(chip, true); - if (rc < 0) - goto error; - - /* poll for VREG_OK high */ - rc = qpnp_ab_poll_vreg_ok(chip, true, poll_time_us); - if (rc < 0) - goto error; - - /* - * As per the hardware recommendation, Wait for ~10 ms after - * polling for VREG_OK before changing the configuration when - * exiting from AOD mode. - */ - - usleep_range(10000, 10001); - - rc = qpnp_ibb_aod_config(chip, false); + if (chip->ibb.pd_control) { + const int rc = qpnp_ibb_pd_control(chip, en); if (rc < 0) - goto error; - - if (chip->ibb.pd_control) { - rc = qpnp_ibb_pd_control(chip, true); - if (rc < 0) - goto error; - } - - if (chip->ab.pd_control) { - rc = qpnp_ab_pd_control(chip, true); - if (rc < 0) - goto error; - } - } else if (mode == REGULATOR_MODE_IDLE) { - if (chip->ab.aod_entry_poll_time_ms > 0) - poll_time_us = chip->ab.aod_entry_poll_time_ms * 1000; - - /* poll for VREG_OK low */ - rc = qpnp_ab_poll_vreg_ok(chip, false, poll_time_us); - if (rc < 0) - goto error; - - if (chip->ibb.pd_control) { - rc = qpnp_ibb_pd_control(chip, false); - if (rc < 0) - goto error; - } - - if (chip->ab.pd_control) { - rc = qpnp_ab_pd_control(chip, false); - if (rc < 0) - goto error; - } + return rc; + } - val = 0xF1; - } else if (mode == REGULATOR_MODE_STANDBY) { - /* Restore the normal configuration without any delay */ - rc = qpnp_ibb_aod_config(chip, false); + if (chip->ab.pd_control) { + const int rc = qpnp_ab_pd_control(chip, en); if (rc < 0) - goto error; - - if (chip->ibb.pd_control) { - rc = qpnp_ibb_pd_control(chip, true); - if (rc < 0) - goto error; - } - - if (chip->ab.pd_control) { - rc = qpnp_ab_pd_control(chip, true); - if (rc < 0) - goto error; - } + return rc; } - rc = qpnp_amoled_write(chip, AB_LDO_SW_DBG_CTL(chip), &val, 1); -error: - if (rc < 0) - pr_err("Failed to configure for mode %d\n", mode); + return 0; } static void qpnp_amoled_vout_override_work(struct work_struct *work) @@ -495,7 +292,7 @@ static int qpnp_ab_ibb_regulator_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct qpnp_amoled *chip = rdev_get_drvdata(rdev); - unsigned int last_mode; + int rc; if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_STANDBY && mode != REGULATOR_MODE_IDLE) { @@ -503,17 +300,21 @@ static int qpnp_ab_ibb_regulator_set_mode(struct regulator_dev *rdev, return -EINVAL; } - pr_debug("mode: %d\n", mode); if (mode == chip->ab.vreg.mode || mode == chip->ibb.vreg.mode) return 0; - mutex_lock(&chip->reg_lock); - last_mode = chip->ab.vreg.mode; - chip->ab.vreg.mode = chip->ibb.vreg.mode = mode; - mutex_unlock(&chip->reg_lock); + pr_debug("mode: %d\n", mode); + + if (mode == REGULATOR_MODE_NORMAL || mode == REGULATOR_MODE_STANDBY) { + rc = qpnp_amoled_pd_control(chip, true); + } else if (mode == REGULATOR_MODE_IDLE) { + rc = qpnp_amoled_pd_control(chip, false); + } - if (last_mode == REGULATOR_MODE_IDLE || mode == REGULATOR_MODE_IDLE) - queue_work(chip->wq, &chip->aod_work); + if (!rc) + chip->ab.vreg.mode = chip->ibb.vreg.mode = mode; + else + pr_err("Failed to configure for mode %d\n", mode); if (chip->oledb.vout_override) { cancel_delayed_work_sync(&chip->vout_work); @@ -523,6 +324,7 @@ static int qpnp_ab_ibb_regulator_set_mode(struct regulator_dev *rdev, queue_delayed_work(chip->wq, &chip->vout_work, delay); } } + return 0; } @@ -773,9 +575,6 @@ static int qpnp_amoled_parse_dt(struct qpnp_amoled *chip) "qcom,swire-control"); chip->ab.pd_control = of_property_read_bool(temp, "qcom,aod-pd-control"); - of_property_read_u32(temp, - "qcom,aod-entry-poll-time-ms", - &chip->ab.aod_entry_poll_time_ms); break; case IBB_PERIPH_TYPE: chip->ibb_base = base; @@ -823,7 +622,6 @@ static int qpnp_amoled_regulator_probe(struct platform_device *pdev) } mutex_init(&chip->reg_lock); - INIT_WORK(&chip->aod_work, qpnp_amoled_aod_work); INIT_DELAYED_WORK(&chip->vout_work, qpnp_amoled_vout_override_work); chip->dev = &pdev->dev; @@ -858,7 +656,6 @@ static int qpnp_amoled_regulator_remove(struct platform_device *pdev) { struct qpnp_amoled *chip = dev_get_drvdata(&pdev->dev); - cancel_work_sync(&chip->aod_work); destroy_workqueue(chip->wq); return 0; }