Loading Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt +4 −1 Original line number Diff line number Diff line Loading @@ -54,7 +54,10 @@ 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-trim-steps-from-center : The number of steps to trim the OVP threshold voltage. The possible values can be between -7 to 8. - qcom,avdd-target-voltage-mv: The target voltage desired for the AVDD module in mV. The supported values are: 7900, 7600, 7300, 6400, 6100, 5800. If not specified, default value used is 7600. Example: qcom,leds@d800 { Loading drivers/leds/leds-qpnp-wled.c +96 −28 Original line number Diff line number Diff line Loading @@ -46,10 +46,12 @@ #define QPNP_WLED_VLOOP_COMP_GM_REG(b) (b + 0x56) #define QPNP_WLED_PSM_CTRL_REG(b) (b + 0x5B) #define QPNP_WLED_SC_PRO_REG(b) (b + 0x5E) #define QPNP_WLED_CTRL_SPARE_REG(b) (b + 0xDF) #define QPNP_WLED_TEST1_REG(b) (b + 0xE2) #define QPNP_WLED_TEST4_REG(b) (b + 0xE5) #define QPNP_WLED_REF_7P7_TRIM_REG(b) (b + 0xF2) #define QPNP_WLED_7P7_TRIM_MASK 0xF #define QPNP_WLED_EN_MASK 0x7F #define QPNP_WLED_EN_SHIFT 7 #define QPNP_WLED_FDBK_OP_MASK 0xF8 Loading @@ -76,9 +78,6 @@ #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_AVDD_MIN_TRIM_VALUE -7 #define QPNP_WLED_AVDD_MAX_TRIM_VALUE 8 #define QPNP_WLED_AVDD_TRIM_CENTER_VALUE 7 #define QPNP_WLED_ILIM_MASK 0xF8 #define QPNP_WLED_ILIM_MIN_MA 105 Loading Loading @@ -195,6 +194,12 @@ #define QPNP_WLED_MIN_MSLEEP 20 #define QPNP_WLED_SC_DLY_MS 20 #define NUM_SUPPORTED_AVDD_VOLTAGES 6 #define QPNP_WLED_AVDD_DEFAULT_VOLTAGE_MV 7600 #define QPNP_WLED_AVDD_MIN_TRIM_VALUE 0x0 #define QPNP_WLED_AVDD_MAX_TRIM_VALUE 0xF #define QPNP_WLED_AVDD_SET_BIT BIT(4) /* output feedback mode */ enum qpnp_wled_fdbk_op { QPNP_WLED_FDBK_AUTO, Loading Loading @@ -227,6 +232,18 @@ static u8 qpnp_wled_sink_dbg_regs[] = { 0xe6, }; static int qpnp_wled_avdd_target_voltages[NUM_SUPPORTED_AVDD_VOLTAGES] = { 7900, 7600, 7300, 6400, 6100, 5800, }; static u8 qpnp_wled_ovp_reg_settings[NUM_SUPPORTED_AVDD_VOLTAGES] = { 0x0, 0x0, 0x1, 0x2, 0x2, 0x3, }; static int qpnp_wled_avdd_trim_adjustments[NUM_SUPPORTED_AVDD_VOLTAGES] = { 3, 0, -2, 7, 3, 3, }; /** * qpnp_wled - wed data structure * @ cdev - led class device Loading @@ -238,7 +255,7 @@ static u8 qpnp_wled_sink_dbg_regs[] = { * @ ovp_irq - over voltage protection irq * @ sc_irq - short circuit irq * @ sc_cnt - short circuit irq count * @ avdd_trim_steps_from_center - number of steps to trim from center value * @ avdd_target_voltage_mv - target voltage for AVDD module in mV * @ ctrl_base - base address for wled ctrl * @ sink_base - base address for wled sink * @ ibb_base - base address for IBB(Inverting Buck Boost) Loading Loading @@ -279,7 +296,7 @@ struct qpnp_wled { int ovp_irq; int sc_irq; u32 sc_cnt; u32 avdd_trim_steps_from_center; u32 avdd_target_voltage_mv; u16 ctrl_base; u16 sink_base; u16 mod_freq_khz; Loading Loading @@ -338,6 +355,24 @@ static int qpnp_wled_write_reg(struct qpnp_wled *wled, u8 *data, u16 addr) return rc; } static int qpnp_wled_masked_write_reg(struct qpnp_wled *wled, u8 mask, u8 *data, u16 addr) { u8 reg; int rc; rc = qpnp_wled_read_reg(wled, ®, addr); if (rc < 0) return rc; reg &= ~mask; reg |= *data & mask; rc = qpnp_wled_write_reg(wled, ®, addr); return rc; } static int qpnp_wled_sec_access(struct qpnp_wled *wled, u16 base_addr) { int rc; Loading Loading @@ -1094,29 +1129,58 @@ static int qpnp_wled_config(struct qpnp_wled *wled) if (rc) return rc; if (wled->disp_type_amoled) { /* Configure avdd trim register */ rc = qpnp_wled_sec_access(wled, wled->ctrl_base); if (rc) rc = qpnp_wled_read_reg(wled, ®, QPNP_WLED_CTRL_SPARE_REG(wled->ctrl_base)); if (rc < 0) return rc; /* Check if wled->avdd_trim_steps_from_center is negative */ if ((s32)wled->avdd_trim_steps_from_center < QPNP_WLED_AVDD_MIN_TRIM_VALUE) { wled->avdd_trim_steps_from_center = QPNP_WLED_AVDD_MIN_TRIM_VALUE; } else if ((s32)wled->avdd_trim_steps_from_center > QPNP_WLED_AVDD_MAX_TRIM_VALUE) { wled->avdd_trim_steps_from_center = QPNP_WLED_AVDD_MAX_TRIM_VALUE; /* * Configure TRIM_REG only if disp_type_amoled and it has * not already been programmed by bootloader. */ if (wled->disp_type_amoled && !(reg & QPNP_WLED_AVDD_SET_BIT)) { for (i = 0; i < NUM_SUPPORTED_AVDD_VOLTAGES; i++) { if (wled->avdd_target_voltage_mv == qpnp_wled_avdd_target_voltages[i]) break; } reg = wled->avdd_trim_steps_from_center + QPNP_WLED_AVDD_TRIM_CENTER_VALUE; if (i == NUM_SUPPORTED_AVDD_VOLTAGES) { dev_err(&wled->spmi->dev, "Invalid avdd target voltage specified in device tree\n"); return -EINVAL; } /* Update WLED_OVP register based on desired target voltage */ reg = qpnp_wled_ovp_reg_settings[i]; rc = qpnp_wled_write_reg(wled, ®, QPNP_WLED_OVP_REG(wled->ctrl_base)); if (rc) return rc; /* Update WLED_TRIM register based on desired target voltage */ rc = qpnp_wled_read_reg(wled, ®, QPNP_WLED_REF_7P7_TRIM_REG(wled->ctrl_base)); if (rc) return rc; reg += qpnp_wled_avdd_trim_adjustments[i]; if ((s8)reg < QPNP_WLED_AVDD_MIN_TRIM_VALUE || (s8)reg > QPNP_WLED_AVDD_MAX_TRIM_VALUE) { dev_info(&wled->spmi->dev, "adjusted trim %d is not within range, capping it\n", (s8)reg); if ((s8)reg < QPNP_WLED_AVDD_MIN_TRIM_VALUE) reg = QPNP_WLED_AVDD_MIN_TRIM_VALUE; else reg = QPNP_WLED_AVDD_MAX_TRIM_VALUE; } rc = qpnp_wled_sec_access(wled, wled->ctrl_base); if (rc) return rc; rc = qpnp_wled_masked_write_reg(wled, QPNP_WLED_7P7_TRIM_MASK, ®, QPNP_WLED_REF_7P7_TRIM_REG(wled->ctrl_base)); if (rc) return rc; } /* Configure the MODULATION register */ Loading Loading @@ -1443,14 +1507,18 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled) return rc; } wled->avdd_trim_steps_from_center = 0; rc = of_property_read_u32(spmi->dev.of_node, "qcom,avdd-trim-steps-from-center", &temp_val); "qcom,avdd-target-voltage-mv", &temp_val); if (!rc) { wled->avdd_trim_steps_from_center = temp_val; } else if (rc != -EINVAL) { dev_err(&spmi->dev, "Unable to read avdd trim steps from center value\n"); wled->avdd_target_voltage_mv = temp_val; } else { if (rc != -EINVAL) return rc; dev_info(&spmi->dev, "qcom,avdd-target-voltage-mv not specified. Using default value of %d\n", QPNP_WLED_AVDD_DEFAULT_VOLTAGE_MV); wled->avdd_target_voltage_mv = QPNP_WLED_AVDD_DEFAULT_VOLTAGE_MV; } } Loading Loading
Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt +4 −1 Original line number Diff line number Diff line Loading @@ -54,7 +54,10 @@ 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-trim-steps-from-center : The number of steps to trim the OVP threshold voltage. The possible values can be between -7 to 8. - qcom,avdd-target-voltage-mv: The target voltage desired for the AVDD module in mV. The supported values are: 7900, 7600, 7300, 6400, 6100, 5800. If not specified, default value used is 7600. Example: qcom,leds@d800 { Loading
drivers/leds/leds-qpnp-wled.c +96 −28 Original line number Diff line number Diff line Loading @@ -46,10 +46,12 @@ #define QPNP_WLED_VLOOP_COMP_GM_REG(b) (b + 0x56) #define QPNP_WLED_PSM_CTRL_REG(b) (b + 0x5B) #define QPNP_WLED_SC_PRO_REG(b) (b + 0x5E) #define QPNP_WLED_CTRL_SPARE_REG(b) (b + 0xDF) #define QPNP_WLED_TEST1_REG(b) (b + 0xE2) #define QPNP_WLED_TEST4_REG(b) (b + 0xE5) #define QPNP_WLED_REF_7P7_TRIM_REG(b) (b + 0xF2) #define QPNP_WLED_7P7_TRIM_MASK 0xF #define QPNP_WLED_EN_MASK 0x7F #define QPNP_WLED_EN_SHIFT 7 #define QPNP_WLED_FDBK_OP_MASK 0xF8 Loading @@ -76,9 +78,6 @@ #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_AVDD_MIN_TRIM_VALUE -7 #define QPNP_WLED_AVDD_MAX_TRIM_VALUE 8 #define QPNP_WLED_AVDD_TRIM_CENTER_VALUE 7 #define QPNP_WLED_ILIM_MASK 0xF8 #define QPNP_WLED_ILIM_MIN_MA 105 Loading Loading @@ -195,6 +194,12 @@ #define QPNP_WLED_MIN_MSLEEP 20 #define QPNP_WLED_SC_DLY_MS 20 #define NUM_SUPPORTED_AVDD_VOLTAGES 6 #define QPNP_WLED_AVDD_DEFAULT_VOLTAGE_MV 7600 #define QPNP_WLED_AVDD_MIN_TRIM_VALUE 0x0 #define QPNP_WLED_AVDD_MAX_TRIM_VALUE 0xF #define QPNP_WLED_AVDD_SET_BIT BIT(4) /* output feedback mode */ enum qpnp_wled_fdbk_op { QPNP_WLED_FDBK_AUTO, Loading Loading @@ -227,6 +232,18 @@ static u8 qpnp_wled_sink_dbg_regs[] = { 0xe6, }; static int qpnp_wled_avdd_target_voltages[NUM_SUPPORTED_AVDD_VOLTAGES] = { 7900, 7600, 7300, 6400, 6100, 5800, }; static u8 qpnp_wled_ovp_reg_settings[NUM_SUPPORTED_AVDD_VOLTAGES] = { 0x0, 0x0, 0x1, 0x2, 0x2, 0x3, }; static int qpnp_wled_avdd_trim_adjustments[NUM_SUPPORTED_AVDD_VOLTAGES] = { 3, 0, -2, 7, 3, 3, }; /** * qpnp_wled - wed data structure * @ cdev - led class device Loading @@ -238,7 +255,7 @@ static u8 qpnp_wled_sink_dbg_regs[] = { * @ ovp_irq - over voltage protection irq * @ sc_irq - short circuit irq * @ sc_cnt - short circuit irq count * @ avdd_trim_steps_from_center - number of steps to trim from center value * @ avdd_target_voltage_mv - target voltage for AVDD module in mV * @ ctrl_base - base address for wled ctrl * @ sink_base - base address for wled sink * @ ibb_base - base address for IBB(Inverting Buck Boost) Loading Loading @@ -279,7 +296,7 @@ struct qpnp_wled { int ovp_irq; int sc_irq; u32 sc_cnt; u32 avdd_trim_steps_from_center; u32 avdd_target_voltage_mv; u16 ctrl_base; u16 sink_base; u16 mod_freq_khz; Loading Loading @@ -338,6 +355,24 @@ static int qpnp_wled_write_reg(struct qpnp_wled *wled, u8 *data, u16 addr) return rc; } static int qpnp_wled_masked_write_reg(struct qpnp_wled *wled, u8 mask, u8 *data, u16 addr) { u8 reg; int rc; rc = qpnp_wled_read_reg(wled, ®, addr); if (rc < 0) return rc; reg &= ~mask; reg |= *data & mask; rc = qpnp_wled_write_reg(wled, ®, addr); return rc; } static int qpnp_wled_sec_access(struct qpnp_wled *wled, u16 base_addr) { int rc; Loading Loading @@ -1094,29 +1129,58 @@ static int qpnp_wled_config(struct qpnp_wled *wled) if (rc) return rc; if (wled->disp_type_amoled) { /* Configure avdd trim register */ rc = qpnp_wled_sec_access(wled, wled->ctrl_base); if (rc) rc = qpnp_wled_read_reg(wled, ®, QPNP_WLED_CTRL_SPARE_REG(wled->ctrl_base)); if (rc < 0) return rc; /* Check if wled->avdd_trim_steps_from_center is negative */ if ((s32)wled->avdd_trim_steps_from_center < QPNP_WLED_AVDD_MIN_TRIM_VALUE) { wled->avdd_trim_steps_from_center = QPNP_WLED_AVDD_MIN_TRIM_VALUE; } else if ((s32)wled->avdd_trim_steps_from_center > QPNP_WLED_AVDD_MAX_TRIM_VALUE) { wled->avdd_trim_steps_from_center = QPNP_WLED_AVDD_MAX_TRIM_VALUE; /* * Configure TRIM_REG only if disp_type_amoled and it has * not already been programmed by bootloader. */ if (wled->disp_type_amoled && !(reg & QPNP_WLED_AVDD_SET_BIT)) { for (i = 0; i < NUM_SUPPORTED_AVDD_VOLTAGES; i++) { if (wled->avdd_target_voltage_mv == qpnp_wled_avdd_target_voltages[i]) break; } reg = wled->avdd_trim_steps_from_center + QPNP_WLED_AVDD_TRIM_CENTER_VALUE; if (i == NUM_SUPPORTED_AVDD_VOLTAGES) { dev_err(&wled->spmi->dev, "Invalid avdd target voltage specified in device tree\n"); return -EINVAL; } /* Update WLED_OVP register based on desired target voltage */ reg = qpnp_wled_ovp_reg_settings[i]; rc = qpnp_wled_write_reg(wled, ®, QPNP_WLED_OVP_REG(wled->ctrl_base)); if (rc) return rc; /* Update WLED_TRIM register based on desired target voltage */ rc = qpnp_wled_read_reg(wled, ®, QPNP_WLED_REF_7P7_TRIM_REG(wled->ctrl_base)); if (rc) return rc; reg += qpnp_wled_avdd_trim_adjustments[i]; if ((s8)reg < QPNP_WLED_AVDD_MIN_TRIM_VALUE || (s8)reg > QPNP_WLED_AVDD_MAX_TRIM_VALUE) { dev_info(&wled->spmi->dev, "adjusted trim %d is not within range, capping it\n", (s8)reg); if ((s8)reg < QPNP_WLED_AVDD_MIN_TRIM_VALUE) reg = QPNP_WLED_AVDD_MIN_TRIM_VALUE; else reg = QPNP_WLED_AVDD_MAX_TRIM_VALUE; } rc = qpnp_wled_sec_access(wled, wled->ctrl_base); if (rc) return rc; rc = qpnp_wled_masked_write_reg(wled, QPNP_WLED_7P7_TRIM_MASK, ®, QPNP_WLED_REF_7P7_TRIM_REG(wled->ctrl_base)); if (rc) return rc; } /* Configure the MODULATION register */ Loading Loading @@ -1443,14 +1507,18 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled) return rc; } wled->avdd_trim_steps_from_center = 0; rc = of_property_read_u32(spmi->dev.of_node, "qcom,avdd-trim-steps-from-center", &temp_val); "qcom,avdd-target-voltage-mv", &temp_val); if (!rc) { wled->avdd_trim_steps_from_center = temp_val; } else if (rc != -EINVAL) { dev_err(&spmi->dev, "Unable to read avdd trim steps from center value\n"); wled->avdd_target_voltage_mv = temp_val; } else { if (rc != -EINVAL) return rc; dev_info(&spmi->dev, "qcom,avdd-target-voltage-mv not specified. Using default value of %d\n", QPNP_WLED_AVDD_DEFAULT_VOLTAGE_MV); wled->avdd_target_voltage_mv = QPNP_WLED_AVDD_DEFAULT_VOLTAGE_MV; } } Loading