diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt index 07f3fd274658..15924f659e61 100644 --- a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt @@ -68,9 +68,12 @@ Optional properties for WLED: - qcom,cons-sync-write-delay-us : Specify in 'us' the duration of delay between two consecutive writes to SYNC register. - qcom,sc-deb-cycles : debounce time for short circuit detection +- qcom,loop-ea-gm : control the gm for gm stage in control loop. default is 3. +- qcom,loop-auto-gm-en : A boolean property to specify if auto gm is enabled. +- qcom,loop-auto-gm-thresh : Specify auto gm threshold if "loop-auto-gm-en" is defined. + Supported values are: 0 - 3. Optional properties if 'qcom,disp-type-amoled' is mentioned in DT: -- qcom,loop-ea-gm : control the gm for gm stage in control loop. default is 3. - qcom,loop-comp-res-kohm : control to select the compensation resistor in kohm. default is 320. - qcom,vref-psm-mv : reference psm voltage in mv. default for amoled is 450. - qcom,avdd-mode-spmi: Boolean property to enable AMOLED_VOUT programming via SPMI. If not specified, diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c index 97cfa813f4ce..0e359962ca37 100644 --- a/drivers/leds/leds-qpnp-wled.c +++ b/drivers/leds/leds-qpnp-wled.c @@ -69,11 +69,18 @@ #define QPNP_WLED_LOOP_COMP_RES_STEP_KOHM 20 #define QPNP_WLED_LOOP_COMP_RES_MIN_KOHM 20 #define QPNP_WLED_LOOP_COMP_RES_MAX_KOHM 320 -#define QPNP_WLED_VLOOP_COMP_GM_MASK 0xF0 +#define QPNP_WLED_VLOOP_COMP_GM_MASK GENMASK(3, 0) #define QPNP_WLED_VLOOP_COMP_GM_OVERWRITE 0x80 -#define QPNP_WLED_LOOP_EA_GM_DFLT_AMOLED 0x03 +#define QPNP_WLED_VLOOP_COMP_AUTO_GM_EN BIT(6) +#define QPNP_WLED_VLOOP_COMP_AUTO_GM_THRESH_MASK GENMASK(5, 4) +#define QPNP_WLED_VLOOP_COMP_AUTO_GM_THRESH_SHIFT 4 +#define QPNP_WLED_LOOP_EA_GM_DFLT_AMOLED_PMI8994 0x03 +#define QPNP_WLED_LOOP_GM_DFLT_AMOLED_PMICOBALT 0x09 +#define QPNP_WLED_LOOP_GM_DFLT_WLED 0x09 #define QPNP_WLED_LOOP_EA_GM_MIN 0x0 #define QPNP_WLED_LOOP_EA_GM_MAX 0xF +#define QPNP_WLED_LOOP_AUTO_GM_THRESH_MAX 3 +#define QPNP_WLED_LOOP_AUTO_GM_DFLT_THRESH 1 #define QPNP_WLED_VREF_PSM_MASK 0xF8 #define QPNP_WLED_VREF_PSM_STEP_MV 50 #define QPNP_WLED_VREF_PSM_MIN_MV 400 @@ -319,6 +326,8 @@ static struct wled_vref_setting vref_setting_pmicobalt = { * @ cons_sync_write_delay_us - delay between two consecutive writes to SYNC * @ strings - supported list of strings * @ num_strings - number of strings + * @ loop_auto_gm_thresh - the clamping level for auto gm + * @ loop_auto_gm_en - select if auto gm is enabled * @ 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 @@ -362,6 +371,8 @@ struct qpnp_wled { u16 cons_sync_write_delay_us; u8 strings[QPNP_WLED_MAX_STRINGS]; u8 num_strings; + u8 loop_auto_gm_thresh; + bool loop_auto_gm_en; bool avdd_mode_spmi; bool en_9b_dim_res; bool en_phase_stag; @@ -987,24 +998,6 @@ static int qpnp_wled_set_disp(struct qpnp_wled *wled, u16 base_addr) if (rc) return rc; - /* Configure the LOOP COMP GM register for AMOLED */ - if (wled->loop_ea_gm < QPNP_WLED_LOOP_EA_GM_MIN) - wled->loop_ea_gm = QPNP_WLED_LOOP_EA_GM_MIN; - else if (wled->loop_ea_gm > QPNP_WLED_LOOP_EA_GM_MAX) - wled->loop_ea_gm = QPNP_WLED_LOOP_EA_GM_MAX; - - rc = qpnp_wled_read_reg(wled, ®, - QPNP_WLED_VLOOP_COMP_GM_REG(wled->ctrl_base)); - if (rc < 0) - return rc; - - reg &= QPNP_WLED_VLOOP_COMP_GM_MASK; - reg |= (wled->loop_ea_gm | QPNP_WLED_VLOOP_COMP_GM_OVERWRITE); - rc = qpnp_wled_write_reg(wled, reg, - QPNP_WLED_VLOOP_COMP_GM_REG(wled->ctrl_base)); - if (rc) - return rc; - /* Configure the CTRL TEST4 register for AMOLED */ rc = qpnp_wled_read_reg(wled, ®, QPNP_WLED_TEST4_REG(wled->ctrl_base)); @@ -1084,6 +1077,45 @@ static bool is_avdd_trim_adjustment_required(struct qpnp_wled *wled) return !(reg & QPNP_WLED_AVDD_SET_BIT); } +static int qpnp_wled_gm_config(struct qpnp_wled *wled) +{ + int rc; + u8 mask = 0, reg = 0; + + /* Configure the LOOP COMP GM register */ + if (wled->pmic_rev_id->pmic_subtype == PMICOBALT_SUBTYPE || + wled->pmic_rev_id->pmic_subtype == PM2FALCON_SUBTYPE) { + if (wled->loop_auto_gm_en) + reg |= QPNP_WLED_VLOOP_COMP_AUTO_GM_EN; + + if (wled->loop_auto_gm_thresh > + QPNP_WLED_LOOP_AUTO_GM_THRESH_MAX) + wled->loop_auto_gm_thresh = + QPNP_WLED_LOOP_AUTO_GM_THRESH_MAX; + + reg |= wled->loop_auto_gm_thresh << + QPNP_WLED_VLOOP_COMP_AUTO_GM_THRESH_SHIFT; + mask |= QPNP_WLED_VLOOP_COMP_AUTO_GM_EN | + QPNP_WLED_VLOOP_COMP_AUTO_GM_THRESH_MASK; + } + + if (wled->loop_ea_gm < QPNP_WLED_LOOP_EA_GM_MIN) + wled->loop_ea_gm = QPNP_WLED_LOOP_EA_GM_MIN; + else if (wled->loop_ea_gm > QPNP_WLED_LOOP_EA_GM_MAX) + wled->loop_ea_gm = QPNP_WLED_LOOP_EA_GM_MAX; + + reg |= wled->loop_ea_gm | QPNP_WLED_VLOOP_COMP_GM_OVERWRITE; + mask |= QPNP_WLED_VLOOP_COMP_GM_MASK | + QPNP_WLED_VLOOP_COMP_GM_OVERWRITE; + + rc = qpnp_wled_masked_write_reg(wled, mask, ®, + QPNP_WLED_VLOOP_COMP_GM_REG(wled->ctrl_base)); + if (rc) + pr_err("write VLOOP_COMP_GM_REG failed, rc=%d]\n", rc); + + return rc; +} + static int qpnp_wled_ovp_config(struct qpnp_wled *wled) { int rc, i, *ovp_table; @@ -1317,6 +1349,13 @@ static int qpnp_wled_config(struct qpnp_wled *wled) return rc; } + /* Configure VLOOP_COMP_GM register */ + rc = qpnp_wled_gm_config(wled); + if (rc < 0) { + pr_err("Error in configureing wled gm, rc=%d\n", rc); + return rc; + } + /* Configure the ILIM register */ rc = qpnp_wled_ilim_config(wled); if (rc < 0) { @@ -1689,16 +1728,6 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled) return rc; } - wled->loop_ea_gm = QPNP_WLED_LOOP_EA_GM_DFLT_AMOLED; - rc = of_property_read_u32(pdev->dev.of_node, - "qcom,loop-ea-gm", &temp_val); - if (!rc) { - wled->loop_ea_gm = temp_val; - } else if (rc != -EINVAL) { - dev_err(&pdev->dev, "Unable to read loop-ea-gm\n"); - return rc; - } - wled->avdd_mode_spmi = of_property_read_bool(pdev->dev.of_node, "qcom,avdd-mode-spmi"); @@ -1713,6 +1742,43 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled) } } + if (wled->disp_type_amoled) { + if (wled->pmic_rev_id->pmic_subtype == PMICOBALT_SUBTYPE || + wled->pmic_rev_id->pmic_subtype == PM2FALCON_SUBTYPE) + wled->loop_ea_gm = + QPNP_WLED_LOOP_GM_DFLT_AMOLED_PMICOBALT; + else + wled->loop_ea_gm = + QPNP_WLED_LOOP_EA_GM_DFLT_AMOLED_PMI8994; + } else { + wled->loop_ea_gm = QPNP_WLED_LOOP_GM_DFLT_WLED; + } + + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,loop-ea-gm", &temp_val); + if (!rc) { + wled->loop_ea_gm = temp_val; + } else if (rc != -EINVAL) { + dev_err(&pdev->dev, "Unable to read loop-ea-gm\n"); + return rc; + } + + if (wled->pmic_rev_id->pmic_subtype == PMICOBALT_SUBTYPE || + wled->pmic_rev_id->pmic_subtype == PM2FALCON_SUBTYPE) { + wled->loop_auto_gm_en = + of_property_read_bool(pdev->dev.of_node, + "qcom,loop-auto-gm-en"); + wled->loop_auto_gm_thresh = QPNP_WLED_LOOP_AUTO_GM_DFLT_THRESH; + rc = of_property_read_u8(pdev->dev.of_node, + "qcom,loop-auto-gm-thresh", + &wled->loop_auto_gm_thresh); + if (rc && rc != -EINVAL) { + dev_err(&pdev->dev, + "Unable to read loop-auto-gm-thresh\n"); + return rc; + } + } + wled->sc_deb_cycles = QPNP_WLED_SC_DEB_CYCLES_DFLT; rc = of_property_read_u32(pdev->dev.of_node, "qcom,sc-deb-cycles", &temp_val);