Currently, auto calibration logic checks only for OVP_FAULT bit to be set in FAULT_STATUS register to detect OVP fault. This works well for WLED4 type. However, WLED5 type has OVP_PRE_ALARM bit which can indicate a potential OVP fault. Use that as well for detecting OVP fault and run auto calibration to fix the sink configuration. Signed-off-by: Kiran Gunda <kgunda@xxxxxxxxxxxxxx> --- drivers/video/backlight/qcom-wled.c | 90 ++++++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 2 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index edbbcb2..5079f1f 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -27,6 +27,7 @@ #define WLED3_CTRL_REG_ILIM_FAULT_BIT BIT(0) #define WLED3_CTRL_REG_OVP_FAULT_BIT BIT(1) #define WLED4_CTRL_REG_SC_FAULT_BIT BIT(2) +#define WLED5_CTRL_REG_OVP_PRE_ALARM_BIT BIT(4) #define WLED3_CTRL_REG_INT_RT_STS 0x10 #define WLED3_CTRL_REG_OVP_FAULT_STATUS BIT(1) @@ -104,6 +105,10 @@ #define WLED4_SINK_REG_BRIGHT(n) (0x57 + (n * 0x10)) +/* WLED5 specific control registers */ +#define WLED5_CTRL_REG_OVP_INT_CTL 0x5f +#define WLED5_CTRL_REG_OVP_INT_TIMER_MASK GENMASK(2, 0) + /* WLED5 specific sink registers */ #define WLED5_SINK_REG_MOD_A_EN 0x50 #define WLED5_SINK_REG_MOD_B_EN 0x60 @@ -394,11 +399,67 @@ static int wled4_ovp_fault_status(struct wled *wled, bool *fault_set) return rc; } +static int wled5_ovp_fault_status(struct wled *wled, bool *fault_set) +{ + int rc; + u32 int_rt_sts, fault_sts; + + *fault_set = false; + rc = regmap_read(wled->regmap, + wled->ctrl_addr + WLED3_CTRL_REG_INT_RT_STS, + &int_rt_sts); + if (rc < 0) { + dev_err(wled->dev, "Failed to read INT_RT_STS rc=%d\n", rc); + return rc; + } + + rc = regmap_read(wled->regmap, + wled->ctrl_addr + WLED3_CTRL_REG_FAULT_STATUS, + &fault_sts); + if (rc < 0) { + dev_err(wled->dev, "Failed to read FAULT_STATUS rc=%d\n", rc); + return rc; + } + + if (int_rt_sts & WLED3_CTRL_REG_OVP_FAULT_STATUS) + *fault_set = true; + + if (fault_sts & (WLED3_CTRL_REG_OVP_FAULT_BIT | + WLED5_CTRL_REG_OVP_PRE_ALARM_BIT)) + *fault_set = true; + + if (*fault_set) + dev_dbg(wled->dev, "WLED OVP fault detected, int_rt_sts=0x%x fault_sts=0x%x\n", + int_rt_sts, fault_sts); + + return rc; +} + static int wled4_ovp_delay(struct wled *wled) { return WLED_SOFT_START_DLY_US; } +static int wled5_ovp_delay(struct wled *wled) +{ + int rc, delay_us; + u32 val; + u8 ovp_timer_ms[8] = {1, 2, 4, 8, 12, 16, 20, 24}; + + /* For WLED5, get the delay based on OVP timer */ + rc = regmap_read(wled->regmap, wled->ctrl_addr + + WLED5_CTRL_REG_OVP_INT_CTL, &val); + if (rc < 0) + delay_us = + ovp_timer_ms[val & WLED5_CTRL_REG_OVP_INT_TIMER_MASK] * 1000; + else + delay_us = 2 * WLED_SOFT_START_DLY_US; + + dev_dbg(wled->dev, "delay_time_us: %d\n", *delay_us); + + return delay_us; +} + static int wled_update_status(struct backlight_device *bl) { struct wled *wled = bl_get_data(bl); @@ -736,9 +797,32 @@ static bool wled_auto_detection_required(struct wled *wled) if (!wled->auto_detection_ovp_count) { wled->start_ovp_fault_time = ktime_get(); wled->auto_detection_ovp_count++; - } else { + return false; + } + + if (wled->version == 5) { + /* + * WLED5 has OVP fault density interrupt configuration i.e. to + * count the number of OVP alarms for a certain duration before + * triggering OVP fault interrupt. By default, number of OVP + * fault events counted before an interrupt is fired is 32 and + * the time interval is 12 ms. If we see more than one OVP fault + * interrupt, then that should qualify for a real OVP fault + * condition to run auto calibration algorithm. + */ + + if (wled->auto_detection_ovp_count > 1) { + elapsed_time_us = ktime_us_delta(ktime_get(), + wled->start_ovp_fault_time); + wled->auto_detection_ovp_count = 0; + dev_dbg(wled->dev, "Elapsed time: %lld us\n", + elapsed_time_us); + return true; + } + wled->auto_detection_ovp_count++; + } else if (wled->version == 4) { elapsed_time_us = ktime_us_delta(ktime_get(), - wled->start_ovp_fault_time); + wled->start_ovp_fault_time); if (elapsed_time_us > WLED_AUTO_DETECT_CNT_DLY_US) wled->auto_detection_ovp_count = 0; else @@ -1424,6 +1508,8 @@ static int wled_configure(struct wled *wled) wled->wled_set_brightness = wled5_set_brightness; wled->wled_sync_toggle = wled5_sync_toggle; wled->cabc_config = wled5_cabc_config; + wled->wled_ovp_fault_status = wled5_ovp_fault_status; + wled->wled_ovp_delay = wled5_ovp_delay; wled->max_string_count = 4; prop_addr = of_get_address(dev->of_node, 1, NULL, NULL); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project