Loading Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt +5 −0 Original line number Diff line number Diff line Loading @@ -94,6 +94,11 @@ platforms. The PMIC is connected to the host processor via SPMI bus. Definition: Interrupt names associated with the interrupts. Currently supported interrupts are "sc-irq" and "ovp-irq". - qcom,auto-calibration Usage: optional Value type: <bool> Definition: Enables auto-calibration of the WLED sink configuration. Example: qcom-wled@d800 { Loading drivers/video/backlight/qcom-spmi-wled.c +308 −8 Original line number Diff line number Diff line Loading @@ -38,11 +38,14 @@ #define WLED_CTRL_SC_FAULT_BIT BIT(2) #define WLED_CTRL_INT_RT_STS 0x10 #define WLED_CTRL_OVP_FLT_RT_STS_BIT BIT(1) #define WLED_CTRL_MOD_ENABLE 0x46 #define WLED_CTRL_MOD_EN_MASK BIT(7) #define WLED_CTRL_MODULE_EN_SHIFT 7 #define WLED_CTRL_FDBK_OP 0x48 #define WLED_CTRL_SWITCH_FREQ 0x4c #define WLED_CTRL_SWITCH_FREQ_MASK GENMASK(3, 0) Loading Loading @@ -99,6 +102,7 @@ struct wled_config { int ovp_irq; bool en_cabc; bool ext_pfet_sc_pro_en; bool auto_calib_enabled; }; struct wled { Loading @@ -108,18 +112,25 @@ struct wled { struct mutex lock; struct wled_config cfg; ktime_t last_sc_event_time; ktime_t start_ovp_fault_time; u16 sink_addr; u16 ctrl_addr; u16 auto_calibration_ovp_count; u32 brightness; u32 sc_count; bool prev_state; bool ovp_irq_disabled; bool auto_calib_done; bool force_mod_disable; }; static int wled_module_enable(struct wled *wled, int val) { int rc; if (wled->force_mod_disable) return 0; rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED_CTRL_MOD_ENABLE, WLED_CTRL_MOD_EN_MASK, val << WLED_CTRL_MODULE_EN_SHIFT); Loading Loading @@ -187,13 +198,11 @@ static int wled_set_brightness(struct wled *wled, u16 brightness) v[1] = (brightness >> 8) & 0xf; for (i = 0; (string_cfg >> i) != 0; i++) { if (string_cfg & BIT(i)) { rc = regmap_bulk_write(wled->regmap, wled->sink_addr + WLED_SINK_BRIGHT_LSB_REG(i), v, 2); if (rc < 0) return rc; } } return 0; } Loading Loading @@ -297,6 +306,288 @@ static irqreturn_t wled_sc_irq_handler(int irq, void *_wled) return IRQ_HANDLED; } #define AUTO_CALIB_BRIGHTNESS 200 static int wled_auto_calibrate(struct wled *wled) { int rc = 0, i; u32 sink_config = 0, int_sts; u8 reg = 0, sink_test = 0, sink_valid = 0; u8 string_cfg = wled->cfg.string_cfg; if (wled->auto_calib_done) return 0; /* read configured sink configuration */ rc = regmap_read(wled->regmap, wled->sink_addr + WLED_SINK_CURR_SINK_EN, &sink_config); if (rc < 0) { pr_err("Failed to read SINK configuration rc=%d\n", rc); goto failed_calib; } /* disable the module before starting calibration */ rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED_CTRL_MOD_ENABLE, WLED_CTRL_MOD_EN_MASK, 0); if (rc < 0) { pr_err("Failed to disable WLED module rc=%d\n", rc); goto failed_calib; } /* set low brightness across all sinks */ rc = wled_set_brightness(wled, AUTO_CALIB_BRIGHTNESS); if (rc < 0) { pr_err("Failed to set brightness for calibration rc=%d\n", rc); goto failed_calib; } if (wled->cfg.en_cabc) { for (i = 0; (string_cfg >> i) != 0; i++) { reg = 0; rc = regmap_update_bits(wled->regmap, wled->sink_addr + WLED_SINK_CABC_REG(i), WLED_SINK_CABC_MASK, reg); if (rc < 0) goto failed_calib; } } /* disable all sinks */ rc = regmap_write(wled->regmap, wled->sink_addr + WLED_SINK_CURR_SINK_EN, 0); if (rc < 0) { pr_err("Failed to disable all sinks rc=%d\n", rc); goto failed_calib; } /* iterate through the strings one by one */ for (i = 0; (string_cfg >> i) != 0; i++) { sink_test = 1 << (WLED_SINK_CURR_SINK_SHFT + i); /* Enable feedback control */ rc = regmap_write(wled->regmap, wled->ctrl_addr + WLED_CTRL_FDBK_OP, i + 1); if (rc < 0) { pr_err("Failed to enable feedback for SINK %d rc = %d\n", i + 1, rc); goto failed_calib; } /* enable the sink */ rc = regmap_write(wled->regmap, wled->sink_addr + WLED_SINK_CURR_SINK_EN, sink_test); if (rc < 0) { pr_err("Failed to configure SINK %d rc=%d\n", i + 1, rc); goto failed_calib; } /* Enable the module */ rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED_CTRL_MOD_ENABLE, WLED_CTRL_MOD_EN_MASK, WLED_CTRL_MOD_EN_MASK); if (rc < 0) { pr_err("Failed to enable WLED module rc=%d\n", rc); goto failed_calib; } usleep_range(WLED_SOFT_START_DLY_US, WLED_SOFT_START_DLY_US + 1000); rc = regmap_read(wled->regmap, wled->ctrl_addr + WLED_CTRL_INT_RT_STS, &int_sts); if (rc < 0) { pr_err("Error in reading WLED_INT_RT_STS rc=%d\n", rc); goto failed_calib; } if (int_sts & WLED_CTRL_OVP_FAULT_BIT) pr_debug("WLED OVP fault detected with SINK %d\n", i + 1); else sink_valid |= sink_test; /* Disable the module */ rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED_CTRL_MOD_ENABLE, WLED_CTRL_MOD_EN_MASK, 0); if (rc < 0) { pr_err("Failed to disable WLED module rc=%d\n", rc); goto failed_calib; } } if (sink_valid == sink_config) { pr_debug("WLED auto-calibration complete, default sink-config=%x OK!\n", sink_config); } else { pr_warn("Invalid WLED default sink config=%x changing it to=%x\n", sink_config, sink_valid); sink_config = sink_valid; } if (!sink_config) { pr_err("No valid WLED sinks found\n"); wled->force_mod_disable = true; goto failed_calib; } /* write the new sink configuration */ rc = regmap_write(wled->regmap, wled->sink_addr + WLED_SINK_CURR_SINK_EN, sink_config); if (rc < 0) { pr_err("Failed to reconfigure the default sink rc=%d\n", rc); goto failed_calib; } /* MODULATOR_EN setting for valid sinks */ for (i = 0; (string_cfg >> i) != 0; i++) { if (wled->cfg.en_cabc) { reg = WLED_SINK_CABC_EN; rc = regmap_update_bits(wled->regmap, wled->sink_addr + WLED_SINK_CABC_REG(i), WLED_SINK_CABC_MASK, reg); if (rc < 0) goto failed_calib; } if (sink_config & (1 << (WLED_SINK_CURR_SINK_SHFT + i))) reg = WLED_SINK_REG_STR_MOD_EN; else reg = 0x0; /* disable modulator_en for unused sink */ rc = regmap_write(wled->regmap, wled->sink_addr + WLED_SINK_MOD_EN_REG(i), reg); if (rc < 0) { pr_err("Failed to configure MODULATOR_EN rc=%d\n", rc); goto failed_calib; } } /* restore the feedback setting */ rc = regmap_write(wled->regmap, wled->ctrl_addr + WLED_CTRL_FDBK_OP, 0); if (rc < 0) { pr_err("Failed to restore feedback setting rc=%d\n", rc); goto failed_calib; } /* restore brightness */ rc = wled_set_brightness(wled, wled->brightness); if (rc < 0) { pr_err("Failed to set brightness after calibration rc=%d\n", rc); goto failed_calib; } rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED_CTRL_MOD_ENABLE, WLED_CTRL_MOD_EN_MASK, WLED_CTRL_MOD_EN_MASK); if (rc < 0) { pr_err("Failed to enable WLED module rc=%d\n", rc); goto failed_calib; } /* delay for WLED soft-start */ usleep_range(WLED_SOFT_START_DLY_US, WLED_SOFT_START_DLY_US + 1000); wled->auto_calib_done = true; failed_calib: return rc; } #define WLED_AUTO_CAL_OVP_COUNT 5 #define WLED_AUTO_CAL_CNT_DLY_US 1000000 /* 1 second */ static bool wled_auto_cal_required(struct wled *wled) { s64 elapsed_time_us; /* * Check if the OVP fault was an occasional one * or if its firing continuously, the latter qualifies * for an auto-calibration check. */ if (!wled->auto_calibration_ovp_count) { wled->start_ovp_fault_time = ktime_get(); wled->auto_calibration_ovp_count++; } else { elapsed_time_us = ktime_us_delta(ktime_get(), wled->start_ovp_fault_time); if (elapsed_time_us > WLED_AUTO_CAL_CNT_DLY_US) wled->auto_calibration_ovp_count = 0; else wled->auto_calibration_ovp_count++; if (wled->auto_calibration_ovp_count >= WLED_AUTO_CAL_OVP_COUNT) { wled->auto_calibration_ovp_count = 0; return true; } } return false; } static int wled_auto_calibrate_at_init(struct wled *wled) { int rc; u32 fault_status = 0, rt_status = 0; if (!wled->cfg.auto_calib_enabled) return 0; rc = regmap_read(wled->regmap, wled->ctrl_addr + WLED_CTRL_INT_RT_STS, &rt_status); if (rc < 0) pr_err("Failed to read RT status rc=%d\n", rc); rc = regmap_read(wled->regmap, wled->ctrl_addr + WLED_CTRL_FAULT_STATUS, &fault_status); if (rc < 0) pr_err("Failed to read fault status rc=%d\n", rc); if ((rt_status & WLED_CTRL_OVP_FLT_RT_STS_BIT) || (fault_status & WLED_CTRL_OVP_FAULT_BIT)) { mutex_lock(&wled->lock); rc = wled_auto_calibrate(wled); if (!rc) wled->auto_calib_done = true; mutex_unlock(&wled->lock); } return rc; } static void handle_ovp_fault(struct wled *wled) { int rc; if (!wled->cfg.auto_calib_enabled) return; mutex_lock(&wled->lock); if (wled->cfg.ovp_irq > 0 && !wled->ovp_irq_disabled) { disable_irq_nosync(wled->cfg.ovp_irq); wled->ovp_irq_disabled = true; } if (wled_auto_cal_required(wled)) wled_auto_calibrate(wled); if (wled->cfg.ovp_irq > 0 && wled->ovp_irq_disabled) { enable_irq(wled->cfg.ovp_irq); wled->ovp_irq_disabled = false; } mutex_unlock(&wled->lock); } static irqreturn_t wled_ovp_irq_handler(int irq, void *_wled) { struct wled *wled = _wled; Loading @@ -322,6 +613,9 @@ static irqreturn_t wled_ovp_irq_handler(int irq, void *_wled) pr_err("WLED OVP fault detected, int_sts=%x fault_sts= %x\n", int_sts, fault_sts); if (fault_sts & WLED_CTRL_OVP_FAULT_BIT) handle_ovp_fault(wled); return IRQ_HANDLED; } Loading Loading @@ -397,6 +691,10 @@ static int wled_setup(struct wled *wled) return rc; } rc = wled_auto_calibrate_at_init(wled); if (rc < 0) return rc; if (sc_irq >= 0) { rc = devm_request_threaded_irq(&wled->pdev->dev, sc_irq, NULL, wled_sc_irq_handler, IRQF_ONESHOT, Loading Loading @@ -435,7 +733,7 @@ static int wled_setup(struct wled *wled) NULL, wled_ovp_irq_handler, IRQF_ONESHOT, "wled_ovp_irq", wled); if (rc < 0) { dev_err(&wled->pdev->dev, "Unable to request ovp(%d) IRQ(err:%d)\n", pr_err("Unable to request ovp(%d) IRQ(err:%d)\n", ovp_irq, rc); return rc; } Loading @@ -459,7 +757,8 @@ static const struct wled_config wled_config_defaults = { .switch_freq = 11, .string_cfg = 0xf, .en_cabc = 0, .ext_pfet_sc_pro_en = 1, .ext_pfet_sc_pro_en = 0, .auto_calib_enabled = 0, }; struct wled_var_cfg { Loading Loading @@ -566,6 +865,7 @@ static int wled_configure(struct wled *wled, struct device *dev) } bool_opts[] = { { "qcom,en-cabc", &cfg->en_cabc, }, { "qcom,ext-pfet-sc-pro", &cfg->ext_pfet_sc_pro_en, }, { "qcom,auto-calibration", &cfg->auto_calib_enabled, }, }; prop_addr = of_get_address(dev->of_node, 0, NULL, NULL); Loading Loading
Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt +5 −0 Original line number Diff line number Diff line Loading @@ -94,6 +94,11 @@ platforms. The PMIC is connected to the host processor via SPMI bus. Definition: Interrupt names associated with the interrupts. Currently supported interrupts are "sc-irq" and "ovp-irq". - qcom,auto-calibration Usage: optional Value type: <bool> Definition: Enables auto-calibration of the WLED sink configuration. Example: qcom-wled@d800 { Loading
drivers/video/backlight/qcom-spmi-wled.c +308 −8 Original line number Diff line number Diff line Loading @@ -38,11 +38,14 @@ #define WLED_CTRL_SC_FAULT_BIT BIT(2) #define WLED_CTRL_INT_RT_STS 0x10 #define WLED_CTRL_OVP_FLT_RT_STS_BIT BIT(1) #define WLED_CTRL_MOD_ENABLE 0x46 #define WLED_CTRL_MOD_EN_MASK BIT(7) #define WLED_CTRL_MODULE_EN_SHIFT 7 #define WLED_CTRL_FDBK_OP 0x48 #define WLED_CTRL_SWITCH_FREQ 0x4c #define WLED_CTRL_SWITCH_FREQ_MASK GENMASK(3, 0) Loading Loading @@ -99,6 +102,7 @@ struct wled_config { int ovp_irq; bool en_cabc; bool ext_pfet_sc_pro_en; bool auto_calib_enabled; }; struct wled { Loading @@ -108,18 +112,25 @@ struct wled { struct mutex lock; struct wled_config cfg; ktime_t last_sc_event_time; ktime_t start_ovp_fault_time; u16 sink_addr; u16 ctrl_addr; u16 auto_calibration_ovp_count; u32 brightness; u32 sc_count; bool prev_state; bool ovp_irq_disabled; bool auto_calib_done; bool force_mod_disable; }; static int wled_module_enable(struct wled *wled, int val) { int rc; if (wled->force_mod_disable) return 0; rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED_CTRL_MOD_ENABLE, WLED_CTRL_MOD_EN_MASK, val << WLED_CTRL_MODULE_EN_SHIFT); Loading Loading @@ -187,13 +198,11 @@ static int wled_set_brightness(struct wled *wled, u16 brightness) v[1] = (brightness >> 8) & 0xf; for (i = 0; (string_cfg >> i) != 0; i++) { if (string_cfg & BIT(i)) { rc = regmap_bulk_write(wled->regmap, wled->sink_addr + WLED_SINK_BRIGHT_LSB_REG(i), v, 2); if (rc < 0) return rc; } } return 0; } Loading Loading @@ -297,6 +306,288 @@ static irqreturn_t wled_sc_irq_handler(int irq, void *_wled) return IRQ_HANDLED; } #define AUTO_CALIB_BRIGHTNESS 200 static int wled_auto_calibrate(struct wled *wled) { int rc = 0, i; u32 sink_config = 0, int_sts; u8 reg = 0, sink_test = 0, sink_valid = 0; u8 string_cfg = wled->cfg.string_cfg; if (wled->auto_calib_done) return 0; /* read configured sink configuration */ rc = regmap_read(wled->regmap, wled->sink_addr + WLED_SINK_CURR_SINK_EN, &sink_config); if (rc < 0) { pr_err("Failed to read SINK configuration rc=%d\n", rc); goto failed_calib; } /* disable the module before starting calibration */ rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED_CTRL_MOD_ENABLE, WLED_CTRL_MOD_EN_MASK, 0); if (rc < 0) { pr_err("Failed to disable WLED module rc=%d\n", rc); goto failed_calib; } /* set low brightness across all sinks */ rc = wled_set_brightness(wled, AUTO_CALIB_BRIGHTNESS); if (rc < 0) { pr_err("Failed to set brightness for calibration rc=%d\n", rc); goto failed_calib; } if (wled->cfg.en_cabc) { for (i = 0; (string_cfg >> i) != 0; i++) { reg = 0; rc = regmap_update_bits(wled->regmap, wled->sink_addr + WLED_SINK_CABC_REG(i), WLED_SINK_CABC_MASK, reg); if (rc < 0) goto failed_calib; } } /* disable all sinks */ rc = regmap_write(wled->regmap, wled->sink_addr + WLED_SINK_CURR_SINK_EN, 0); if (rc < 0) { pr_err("Failed to disable all sinks rc=%d\n", rc); goto failed_calib; } /* iterate through the strings one by one */ for (i = 0; (string_cfg >> i) != 0; i++) { sink_test = 1 << (WLED_SINK_CURR_SINK_SHFT + i); /* Enable feedback control */ rc = regmap_write(wled->regmap, wled->ctrl_addr + WLED_CTRL_FDBK_OP, i + 1); if (rc < 0) { pr_err("Failed to enable feedback for SINK %d rc = %d\n", i + 1, rc); goto failed_calib; } /* enable the sink */ rc = regmap_write(wled->regmap, wled->sink_addr + WLED_SINK_CURR_SINK_EN, sink_test); if (rc < 0) { pr_err("Failed to configure SINK %d rc=%d\n", i + 1, rc); goto failed_calib; } /* Enable the module */ rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED_CTRL_MOD_ENABLE, WLED_CTRL_MOD_EN_MASK, WLED_CTRL_MOD_EN_MASK); if (rc < 0) { pr_err("Failed to enable WLED module rc=%d\n", rc); goto failed_calib; } usleep_range(WLED_SOFT_START_DLY_US, WLED_SOFT_START_DLY_US + 1000); rc = regmap_read(wled->regmap, wled->ctrl_addr + WLED_CTRL_INT_RT_STS, &int_sts); if (rc < 0) { pr_err("Error in reading WLED_INT_RT_STS rc=%d\n", rc); goto failed_calib; } if (int_sts & WLED_CTRL_OVP_FAULT_BIT) pr_debug("WLED OVP fault detected with SINK %d\n", i + 1); else sink_valid |= sink_test; /* Disable the module */ rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED_CTRL_MOD_ENABLE, WLED_CTRL_MOD_EN_MASK, 0); if (rc < 0) { pr_err("Failed to disable WLED module rc=%d\n", rc); goto failed_calib; } } if (sink_valid == sink_config) { pr_debug("WLED auto-calibration complete, default sink-config=%x OK!\n", sink_config); } else { pr_warn("Invalid WLED default sink config=%x changing it to=%x\n", sink_config, sink_valid); sink_config = sink_valid; } if (!sink_config) { pr_err("No valid WLED sinks found\n"); wled->force_mod_disable = true; goto failed_calib; } /* write the new sink configuration */ rc = regmap_write(wled->regmap, wled->sink_addr + WLED_SINK_CURR_SINK_EN, sink_config); if (rc < 0) { pr_err("Failed to reconfigure the default sink rc=%d\n", rc); goto failed_calib; } /* MODULATOR_EN setting for valid sinks */ for (i = 0; (string_cfg >> i) != 0; i++) { if (wled->cfg.en_cabc) { reg = WLED_SINK_CABC_EN; rc = regmap_update_bits(wled->regmap, wled->sink_addr + WLED_SINK_CABC_REG(i), WLED_SINK_CABC_MASK, reg); if (rc < 0) goto failed_calib; } if (sink_config & (1 << (WLED_SINK_CURR_SINK_SHFT + i))) reg = WLED_SINK_REG_STR_MOD_EN; else reg = 0x0; /* disable modulator_en for unused sink */ rc = regmap_write(wled->regmap, wled->sink_addr + WLED_SINK_MOD_EN_REG(i), reg); if (rc < 0) { pr_err("Failed to configure MODULATOR_EN rc=%d\n", rc); goto failed_calib; } } /* restore the feedback setting */ rc = regmap_write(wled->regmap, wled->ctrl_addr + WLED_CTRL_FDBK_OP, 0); if (rc < 0) { pr_err("Failed to restore feedback setting rc=%d\n", rc); goto failed_calib; } /* restore brightness */ rc = wled_set_brightness(wled, wled->brightness); if (rc < 0) { pr_err("Failed to set brightness after calibration rc=%d\n", rc); goto failed_calib; } rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED_CTRL_MOD_ENABLE, WLED_CTRL_MOD_EN_MASK, WLED_CTRL_MOD_EN_MASK); if (rc < 0) { pr_err("Failed to enable WLED module rc=%d\n", rc); goto failed_calib; } /* delay for WLED soft-start */ usleep_range(WLED_SOFT_START_DLY_US, WLED_SOFT_START_DLY_US + 1000); wled->auto_calib_done = true; failed_calib: return rc; } #define WLED_AUTO_CAL_OVP_COUNT 5 #define WLED_AUTO_CAL_CNT_DLY_US 1000000 /* 1 second */ static bool wled_auto_cal_required(struct wled *wled) { s64 elapsed_time_us; /* * Check if the OVP fault was an occasional one * or if its firing continuously, the latter qualifies * for an auto-calibration check. */ if (!wled->auto_calibration_ovp_count) { wled->start_ovp_fault_time = ktime_get(); wled->auto_calibration_ovp_count++; } else { elapsed_time_us = ktime_us_delta(ktime_get(), wled->start_ovp_fault_time); if (elapsed_time_us > WLED_AUTO_CAL_CNT_DLY_US) wled->auto_calibration_ovp_count = 0; else wled->auto_calibration_ovp_count++; if (wled->auto_calibration_ovp_count >= WLED_AUTO_CAL_OVP_COUNT) { wled->auto_calibration_ovp_count = 0; return true; } } return false; } static int wled_auto_calibrate_at_init(struct wled *wled) { int rc; u32 fault_status = 0, rt_status = 0; if (!wled->cfg.auto_calib_enabled) return 0; rc = regmap_read(wled->regmap, wled->ctrl_addr + WLED_CTRL_INT_RT_STS, &rt_status); if (rc < 0) pr_err("Failed to read RT status rc=%d\n", rc); rc = regmap_read(wled->regmap, wled->ctrl_addr + WLED_CTRL_FAULT_STATUS, &fault_status); if (rc < 0) pr_err("Failed to read fault status rc=%d\n", rc); if ((rt_status & WLED_CTRL_OVP_FLT_RT_STS_BIT) || (fault_status & WLED_CTRL_OVP_FAULT_BIT)) { mutex_lock(&wled->lock); rc = wled_auto_calibrate(wled); if (!rc) wled->auto_calib_done = true; mutex_unlock(&wled->lock); } return rc; } static void handle_ovp_fault(struct wled *wled) { int rc; if (!wled->cfg.auto_calib_enabled) return; mutex_lock(&wled->lock); if (wled->cfg.ovp_irq > 0 && !wled->ovp_irq_disabled) { disable_irq_nosync(wled->cfg.ovp_irq); wled->ovp_irq_disabled = true; } if (wled_auto_cal_required(wled)) wled_auto_calibrate(wled); if (wled->cfg.ovp_irq > 0 && wled->ovp_irq_disabled) { enable_irq(wled->cfg.ovp_irq); wled->ovp_irq_disabled = false; } mutex_unlock(&wled->lock); } static irqreturn_t wled_ovp_irq_handler(int irq, void *_wled) { struct wled *wled = _wled; Loading @@ -322,6 +613,9 @@ static irqreturn_t wled_ovp_irq_handler(int irq, void *_wled) pr_err("WLED OVP fault detected, int_sts=%x fault_sts= %x\n", int_sts, fault_sts); if (fault_sts & WLED_CTRL_OVP_FAULT_BIT) handle_ovp_fault(wled); return IRQ_HANDLED; } Loading Loading @@ -397,6 +691,10 @@ static int wled_setup(struct wled *wled) return rc; } rc = wled_auto_calibrate_at_init(wled); if (rc < 0) return rc; if (sc_irq >= 0) { rc = devm_request_threaded_irq(&wled->pdev->dev, sc_irq, NULL, wled_sc_irq_handler, IRQF_ONESHOT, Loading Loading @@ -435,7 +733,7 @@ static int wled_setup(struct wled *wled) NULL, wled_ovp_irq_handler, IRQF_ONESHOT, "wled_ovp_irq", wled); if (rc < 0) { dev_err(&wled->pdev->dev, "Unable to request ovp(%d) IRQ(err:%d)\n", pr_err("Unable to request ovp(%d) IRQ(err:%d)\n", ovp_irq, rc); return rc; } Loading @@ -459,7 +757,8 @@ static const struct wled_config wled_config_defaults = { .switch_freq = 11, .string_cfg = 0xf, .en_cabc = 0, .ext_pfet_sc_pro_en = 1, .ext_pfet_sc_pro_en = 0, .auto_calib_enabled = 0, }; struct wled_var_cfg { Loading Loading @@ -566,6 +865,7 @@ static int wled_configure(struct wled *wled, struct device *dev) } bool_opts[] = { { "qcom,en-cabc", &cfg->en_cabc, }, { "qcom,ext-pfet-sc-pro", &cfg->ext_pfet_sc_pro_en, }, { "qcom,auto-calibration", &cfg->auto_calib_enabled, }, }; prop_addr = of_get_address(dev->of_node, 0, NULL, NULL); Loading