From 0996508e0d446be1f75d707faf5a50d714596a6d Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Fri, 17 Feb 2017 15:48:47 -0800 Subject: [PATCH] leds: qpnp-wled: add support to control PSM dynamically As per the hardware recommendation, keep PSM disabled 10 ms after WLED module is enabled. Enable PSM back when the module is disabled. This is to ensure that PFM mode is operational without the precedence from PSM. Make this configurable through a device tree property. Change-Id: Ic6be160a88be40e94a4a0798646b8aa3f169ab49 Signed-off-by: Subbaraman Narayanamurthy --- .../devicetree/bindings/leds/leds-qpnp-wled.txt | 3 + drivers/leds/leds-qpnp-wled.c | 64 ++++++++++++++++++---- 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt index a77a291a99da..1e6aac56c44e 100644 --- a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt @@ -75,6 +75,9 @@ Optional properties for WLED: - qcom,lcd-auto-pfm-thresh : Specify the auto-pfm threshold, if the headroom voltage level falls below this threshold and auto PFM is enabled, boost controller will enter into PFM mode automatically. +- qcom,lcd-psm-ctrl : A boolean property to specify if PSM needs to be + controlled dynamically when WLED module is enabled + or disabled. Optional properties if 'qcom,disp-type-amoled' is mentioned in DT: - qcom,loop-comp-res-kohm : control to select the compensation resistor in kohm. default is 320. diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c index ba4b2f2c8aab..950244f1e4e8 100644 --- a/drivers/leds/leds-qpnp-wled.c +++ b/drivers/leds/leds-qpnp-wled.c @@ -45,6 +45,7 @@ #define QPNP_WLED_SOFTSTART_RAMP_DLY(b) (b + 0x53) #define QPNP_WLED_VLOOP_COMP_RES_REG(b) (b + 0x55) #define QPNP_WLED_VLOOP_COMP_GM_REG(b) (b + 0x56) +#define QPNP_WLED_EN_PSM_REG(b) (b + 0x5A) #define QPNP_WLED_PSM_CTRL_REG(b) (b + 0x5B) #define QPNP_WLED_LCD_AUTO_PFM_REG(b) (b + 0x5C) #define QPNP_WLED_SC_PRO_REG(b) (b + 0x5E) @@ -83,12 +84,13 @@ #define QPNP_WLED_VREF_PSM_MIN_MV 400 #define QPNP_WLED_VREF_PSM_MAX_MV 750 #define QPNP_WLED_VREF_PSM_DFLT_AMOLED_MV 450 -#define QPNP_WLED_PSM_CTRL_OVERWRITE 0x80 +#define QPNP_WLED_PSM_OVERWRITE_BIT BIT(7) #define QPNP_WLED_LCD_AUTO_PFM_DFLT_THRESH 1 #define QPNP_WLED_LCD_AUTO_PFM_THRESH_MAX 0xF #define QPNP_WLED_LCD_AUTO_PFM_EN_SHIFT 7 #define QPNP_WLED_LCD_AUTO_PFM_EN_BIT BIT(7) #define QPNP_WLED_LCD_AUTO_PFM_THRESH_MASK GENMASK(3, 0) +#define QPNP_WLED_EN_PSM_BIT BIT(7) #define QPNP_WLED_ILIM_MASK GENMASK(2, 0) #define QPNP_WLED_ILIM_OVERWRITE BIT(7) @@ -339,6 +341,7 @@ static struct wled_vref_setting vref_setting_pmi8998 = { * @ lcd_auto_pfm_thresh - the threshold for lcd auto pfm mode * @ loop_auto_gm_en - select if auto gm is enabled * @ lcd_auto_pfm_en - select if auto pfm is enabled in lcd mode + * @ lcd_psm_ctrl - select if psm needs to be controlled in lcd mode * @ avdd_mode_spmi - enable avdd programming via spmi * @ en_9b_dim_res - enable or disable 9bit dimming * @ en_phase_stag - enable or disable phase staggering @@ -384,6 +387,7 @@ struct qpnp_wled { u8 lcd_auto_pfm_thresh; bool loop_auto_gm_en; bool lcd_auto_pfm_en; + bool lcd_psm_ctrl; bool avdd_mode_spmi; bool en_9b_dim_res; bool en_phase_stag; @@ -553,6 +557,30 @@ static int qpnp_wled_set_level(struct qpnp_wled *wled, int level) return 0; } +static int qpnp_wled_psm_config(struct qpnp_wled *wled, bool enable) +{ + int rc; + + if (!wled->lcd_psm_ctrl) + return 0; + + rc = qpnp_wled_masked_write_reg(wled, + QPNP_WLED_EN_PSM_REG(wled->ctrl_base), + QPNP_WLED_EN_PSM_BIT, + enable ? QPNP_WLED_EN_PSM_BIT : 0); + if (rc < 0) + return rc; + + rc = qpnp_wled_masked_write_reg(wled, + QPNP_WLED_PSM_CTRL_REG(wled->ctrl_base), + QPNP_WLED_PSM_OVERWRITE_BIT, + enable ? QPNP_WLED_PSM_OVERWRITE_BIT : 0); + if (rc < 0) + return rc; + + return 0; +} + static int qpnp_wled_module_en(struct qpnp_wled *wled, u16 base_addr, bool state) { @@ -565,21 +593,31 @@ static int qpnp_wled_module_en(struct qpnp_wled *wled, if (rc < 0) return rc; - if (wled->ovp_irq > 0) { - if (state && wled->ovp_irq_disabled) { - /* - * Wait for at least 10ms before enabling OVP fault - * interrupt after enabling the module so that soft - * start is completed. Keep OVP interrupt disabled - * when the module is disabled. - */ - usleep_range(10000, 11000); + /* + * Wait for at least 10ms before enabling OVP fault interrupt after + * enabling the module so that soft start is completed. Also, this + * delay can be used to control PSM during enable when required. Keep + * OVP interrupt disabled when the module is disabled. + */ + if (state) { + usleep_range(10000, 11000); + rc = qpnp_wled_psm_config(wled, false); + if (rc < 0) + return rc; + + if (wled->ovp_irq > 0 && wled->ovp_irq_disabled) { enable_irq(wled->ovp_irq); wled->ovp_irq_disabled = false; - } else if (!state && !wled->ovp_irq_disabled) { + } + } else { + if (wled->ovp_irq > 0 && !wled->ovp_irq_disabled) { disable_irq(wled->ovp_irq); wled->ovp_irq_disabled = true; } + + rc = qpnp_wled_psm_config(wled, true); + if (rc < 0) + return rc; } return 0; @@ -994,7 +1032,7 @@ static int qpnp_wled_set_disp(struct qpnp_wled *wled, u16 base_addr) reg &= QPNP_WLED_VREF_PSM_MASK; reg |= ((wled->vref_psm_mv - QPNP_WLED_VREF_PSM_MIN_MV)/ QPNP_WLED_VREF_PSM_STEP_MV); - reg |= QPNP_WLED_PSM_CTRL_OVERWRITE; + reg |= QPNP_WLED_PSM_OVERWRITE_BIT; rc = qpnp_wled_write_reg(wled, QPNP_WLED_PSM_CTRL_REG(wled->ctrl_base), reg); if (rc) @@ -2078,6 +2116,8 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled) wled->en_ext_pfet_sc_pro = of_property_read_bool(pdev->dev.of_node, "qcom,en-ext-pfet-sc-pro"); + wled->lcd_psm_ctrl = of_property_read_bool(pdev->dev.of_node, + "qcom,lcd-psm-ctrl"); return 0; } -- 2.11.0