Merge "ARM: dts: msm: Enable auto-calibration for WLED on PM660/PMI8998"
This commit is contained in:
commit
07ab04950a
4 changed files with 330 additions and 89 deletions
|
@ -78,6 +78,8 @@ Optional properties for WLED:
|
|||
- qcom,lcd-psm-ctrl : A boolean property to specify if PSM needs to be
|
||||
controlled dynamically when WLED module is enabled
|
||||
or disabled.
|
||||
- qcom,auto-calibration-enable : A boolean property which enables auto-calibration
|
||||
of the WLED sink configuration.
|
||||
|
||||
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.
|
||||
|
|
|
@ -269,6 +269,7 @@
|
|||
qcom,led-strings-list = [00 01 02];
|
||||
qcom,loop-auto-gm-en;
|
||||
qcom,pmic-revid = <&pm660l_revid>;
|
||||
qcom,auto-calibration-enable;
|
||||
status = "ok";
|
||||
};
|
||||
|
||||
|
|
|
@ -634,6 +634,7 @@
|
|||
qcom,en-ext-pfet-sc-pro;
|
||||
qcom,pmic-revid = <&pmi8998_revid>;
|
||||
qcom,loop-auto-gm-en;
|
||||
qcom,auto-calibration-enable;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
|
|
@ -160,18 +160,19 @@
|
|||
#define QPNP_WLED_MOD_EN_SHFT 7
|
||||
#define QPNP_WLED_MOD_EN 1
|
||||
#define QPNP_WLED_GATE_DRV_MASK 0xFE
|
||||
#define QPNP_WLED_SYNC_DLY_MASK 0xF8
|
||||
#define QPNP_WLED_SYNC_DLY_MASK GENMASK(2, 0)
|
||||
#define QPNP_WLED_SYNC_DLY_MIN_US 0
|
||||
#define QPNP_WLED_SYNC_DLY_MAX_US 1400
|
||||
#define QPNP_WLED_SYNC_DLY_STEP_US 200
|
||||
#define QPNP_WLED_DEF_SYNC_DLY_US 400
|
||||
#define QPNP_WLED_FS_CURR_MASK 0xF0
|
||||
#define QPNP_WLED_FS_CURR_MASK GENMASK(3, 0)
|
||||
#define QPNP_WLED_FS_CURR_MIN_UA 0
|
||||
#define QPNP_WLED_FS_CURR_MAX_UA 30000
|
||||
#define QPNP_WLED_FS_CURR_STEP_UA 2500
|
||||
#define QPNP_WLED_CABC_MASK 0x7F
|
||||
#define QPNP_WLED_CABC_MASK 0x80
|
||||
#define QPNP_WLED_CABC_SHIFT 7
|
||||
#define QPNP_WLED_CURR_SINK_SHIFT 4
|
||||
#define QPNP_WLED_CURR_SINK_MASK GENMASK(7, 4)
|
||||
#define QPNP_WLED_BRIGHT_LSB_MASK 0xFF
|
||||
#define QPNP_WLED_BRIGHT_MSB_SHIFT 8
|
||||
#define QPNP_WLED_BRIGHT_MSB_MASK 0x0F
|
||||
|
@ -208,12 +209,14 @@
|
|||
#define QPNP_WLED_SEC_UNLOCK 0xA5
|
||||
|
||||
#define QPNP_WLED_MAX_STRINGS 4
|
||||
#define QPNP_PM660_WLED_MAX_STRINGS 3
|
||||
#define WLED_MAX_LEVEL_4095 4095
|
||||
#define QPNP_WLED_RAMP_DLY_MS 20
|
||||
#define QPNP_WLED_TRIGGER_NONE "none"
|
||||
#define QPNP_WLED_STR_SIZE 20
|
||||
#define QPNP_WLED_MIN_MSLEEP 20
|
||||
#define QPNP_WLED_SC_DLY_MS 20
|
||||
#define QPNP_WLED_SOFT_START_DLY_US 10000
|
||||
|
||||
#define NUM_SUPPORTED_AVDD_VOLTAGES 6
|
||||
#define QPNP_WLED_DFLT_AVDD_MV 7600
|
||||
|
@ -381,6 +384,8 @@ struct qpnp_wled {
|
|||
u16 ramp_ms;
|
||||
u16 ramp_step;
|
||||
u16 cons_sync_write_delay_us;
|
||||
u16 auto_calibration_ovp_count;
|
||||
u16 max_strings;
|
||||
u8 strings[QPNP_WLED_MAX_STRINGS];
|
||||
u8 num_strings;
|
||||
u8 loop_auto_gm_thresh;
|
||||
|
@ -396,6 +401,9 @@ struct qpnp_wled {
|
|||
bool en_ext_pfet_sc_pro;
|
||||
bool prev_state;
|
||||
bool ovp_irq_disabled;
|
||||
bool auto_calib_enabled;
|
||||
bool auto_calib_done;
|
||||
ktime_t start_ovp_fault_time;
|
||||
};
|
||||
|
||||
/* helper to read a pmic register */
|
||||
|
@ -531,7 +539,7 @@ static int qpnp_wled_set_level(struct qpnp_wled *wled, int level)
|
|||
u8 reg;
|
||||
|
||||
/* set brightness registers */
|
||||
for (i = 0; i < wled->num_strings; i++) {
|
||||
for (i = 0; i < wled->max_strings; i++) {
|
||||
reg = level & QPNP_WLED_BRIGHT_LSB_MASK;
|
||||
rc = qpnp_wled_write_reg(wled,
|
||||
QPNP_WLED_BRIGHT_LSB_REG(wled->sink_base,
|
||||
|
@ -600,7 +608,8 @@ static int qpnp_wled_module_en(struct qpnp_wled *wled,
|
|||
* OVP interrupt disabled when the module is disabled.
|
||||
*/
|
||||
if (state) {
|
||||
usleep_range(10000, 11000);
|
||||
usleep_range(QPNP_WLED_SOFT_START_DLY_US,
|
||||
QPNP_WLED_SOFT_START_DLY_US + 1000);
|
||||
rc = qpnp_wled_psm_config(wled, false);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
@ -873,32 +882,25 @@ static ssize_t qpnp_wled_fs_curr_ua_store(struct device *dev,
|
|||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct qpnp_wled *wled = dev_get_drvdata(dev);
|
||||
int data, i, rc, temp;
|
||||
int data, i, rc;
|
||||
u8 reg;
|
||||
|
||||
rc = kstrtoint(buf, 10, &data);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
for (i = 0; i < wled->num_strings; i++) {
|
||||
for (i = 0; i < wled->max_strings; i++) {
|
||||
if (data < QPNP_WLED_FS_CURR_MIN_UA)
|
||||
data = QPNP_WLED_FS_CURR_MIN_UA;
|
||||
else if (data > QPNP_WLED_FS_CURR_MAX_UA)
|
||||
data = QPNP_WLED_FS_CURR_MAX_UA;
|
||||
|
||||
rc = qpnp_wled_read_reg(wled,
|
||||
QPNP_WLED_FS_CURR_REG(wled->sink_base,
|
||||
wled->strings[i]), ®);
|
||||
reg = data / QPNP_WLED_FS_CURR_STEP_UA;
|
||||
rc = qpnp_wled_masked_write_reg(wled,
|
||||
QPNP_WLED_FS_CURR_REG(wled->sink_base, i),
|
||||
QPNP_WLED_FS_CURR_MASK, reg);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
reg &= QPNP_WLED_FS_CURR_MASK;
|
||||
temp = data / QPNP_WLED_FS_CURR_STEP_UA;
|
||||
reg |= temp;
|
||||
rc = qpnp_wled_write_reg(wled,
|
||||
QPNP_WLED_FS_CURR_REG(wled->sink_base,
|
||||
wled->strings[i]), reg);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
wled->fs_curr_ua = data;
|
||||
|
@ -1090,6 +1092,229 @@ static int qpnp_wled_set_disp(struct qpnp_wled *wled, u16 base_addr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define AUTO_CALIB_BRIGHTNESS 16
|
||||
static int wled_auto_calibrate(struct qpnp_wled *wled)
|
||||
{
|
||||
int rc = 0, i;
|
||||
u8 reg = 0, sink_config = 0, sink_test = 0, sink_valid = 0, int_sts;
|
||||
|
||||
mutex_lock(&wled->lock);
|
||||
|
||||
/* disable OVP IRQ */
|
||||
if (wled->ovp_irq > 0 && !wled->ovp_irq_disabled) {
|
||||
disable_irq_nosync(wled->ovp_irq);
|
||||
wled->ovp_irq_disabled = true;
|
||||
}
|
||||
|
||||
/* read configured sink configuration */
|
||||
rc = qpnp_wled_read_reg(wled,
|
||||
QPNP_WLED_CURR_SINK_REG(wled->sink_base), &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 = qpnp_wled_masked_write_reg(wled,
|
||||
QPNP_WLED_MODULE_EN_REG(wled->ctrl_base),
|
||||
QPNP_WLED_MODULE_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 = qpnp_wled_set_level(wled, AUTO_CALIB_BRIGHTNESS);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to set brightness for calibration rc=%d\n", rc);
|
||||
goto failed_calib;
|
||||
}
|
||||
|
||||
/* disable all sinks */
|
||||
rc = qpnp_wled_write_reg(wled,
|
||||
QPNP_WLED_CURR_SINK_REG(wled->sink_base), 0);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to disable all sinks rc=%d\n", rc);
|
||||
goto failed_calib;
|
||||
}
|
||||
|
||||
rc = qpnp_wled_masked_write_reg(wled,
|
||||
QPNP_WLED_MODULE_EN_REG(wled->ctrl_base),
|
||||
QPNP_WLED_MODULE_EN_MASK,
|
||||
QPNP_WLED_MODULE_EN_MASK);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to enable WLED module rc=%d\n", rc);
|
||||
goto failed_calib;
|
||||
}
|
||||
/*
|
||||
* Delay for the WLED soft-start, check the OVP status
|
||||
* only after soft-start is complete
|
||||
*/
|
||||
usleep_range(QPNP_WLED_SOFT_START_DLY_US,
|
||||
QPNP_WLED_SOFT_START_DLY_US + 1000);
|
||||
|
||||
/* iterate through the strings one by one */
|
||||
for (i = 0; i < wled->max_strings; i++) {
|
||||
sink_test = 1 << (QPNP_WLED_CURR_SINK_SHIFT + i);
|
||||
|
||||
/* Enable feedback control */
|
||||
rc = qpnp_wled_write_reg(wled,
|
||||
QPNP_WLED_FDBK_OP_REG(wled->ctrl_base),
|
||||
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 = qpnp_wled_write_reg(wled,
|
||||
QPNP_WLED_CURR_SINK_REG(wled->sink_base), sink_test);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to configure SINK %d rc=%d\n",
|
||||
i + 1, rc);
|
||||
goto failed_calib;
|
||||
}
|
||||
|
||||
/* delay for WLED soft-start */
|
||||
usleep_range(QPNP_WLED_SOFT_START_DLY_US,
|
||||
QPNP_WLED_SOFT_START_DLY_US + 1000);
|
||||
|
||||
rc = qpnp_wled_read_reg(wled,
|
||||
QPNP_WLED_INT_RT_STS(wled->ctrl_base), &int_sts);
|
||||
if (rc < 0) {
|
||||
pr_err("Error in reading WLED_INT_RT_STS rc=%d\n", rc);
|
||||
goto failed_calib;
|
||||
}
|
||||
|
||||
if (int_sts & QPNP_WLED_OVP_FAULT_BIT)
|
||||
pr_debug("WLED OVP fault detected with SINK %d\n",
|
||||
i + 1);
|
||||
else
|
||||
sink_valid |= sink_test;
|
||||
}
|
||||
|
||||
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_warn("No valid WLED sinks found\n");
|
||||
goto failed_calib;
|
||||
}
|
||||
|
||||
rc = qpnp_wled_masked_write_reg(wled,
|
||||
QPNP_WLED_MODULE_EN_REG(wled->ctrl_base),
|
||||
QPNP_WLED_MODULE_EN_MASK, 0);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to disable WLED module rc=%d\n", rc);
|
||||
goto failed_calib;
|
||||
}
|
||||
|
||||
/* write the new sink configuration */
|
||||
rc = qpnp_wled_write_reg(wled,
|
||||
QPNP_WLED_CURR_SINK_REG(wled->sink_base), 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; i < wled->max_strings; i++) {
|
||||
if (sink_config & (1 << (QPNP_WLED_CURR_SINK_SHIFT + i)))
|
||||
reg = (QPNP_WLED_MOD_EN << QPNP_WLED_MOD_EN_SHFT);
|
||||
else
|
||||
reg = 0x0; /* disable modulator_en for unused sink */
|
||||
|
||||
if (wled->dim_mode == QPNP_WLED_DIM_HYBRID)
|
||||
reg &= QPNP_WLED_GATE_DRV_MASK;
|
||||
else
|
||||
reg |= ~QPNP_WLED_GATE_DRV_MASK;
|
||||
|
||||
rc = qpnp_wled_write_reg(wled,
|
||||
QPNP_WLED_MOD_EN_REG(wled->sink_base, i), reg);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to configure MODULATOR_EN rc=%d\n", rc);
|
||||
goto failed_calib;
|
||||
}
|
||||
}
|
||||
|
||||
/* restore the feedback setting */
|
||||
rc = qpnp_wled_write_reg(wled,
|
||||
QPNP_WLED_FDBK_OP_REG(wled->ctrl_base),
|
||||
wled->fdbk_op);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to restore feedback setting rc=%d\n", rc);
|
||||
goto failed_calib;
|
||||
}
|
||||
|
||||
/* restore brightness */
|
||||
rc = qpnp_wled_set_level(wled, wled->cdev.brightness);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to set brightness after calibration rc=%d\n",
|
||||
rc);
|
||||
goto failed_calib;
|
||||
}
|
||||
|
||||
rc = qpnp_wled_masked_write_reg(wled,
|
||||
QPNP_WLED_MODULE_EN_REG(wled->ctrl_base),
|
||||
QPNP_WLED_MODULE_EN_MASK,
|
||||
QPNP_WLED_MODULE_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(QPNP_WLED_SOFT_START_DLY_US,
|
||||
QPNP_WLED_SOFT_START_DLY_US + 1000);
|
||||
|
||||
failed_calib:
|
||||
if (wled->ovp_irq > 0 && wled->ovp_irq_disabled) {
|
||||
enable_irq(wled->ovp_irq);
|
||||
wled->ovp_irq_disabled = false;
|
||||
}
|
||||
mutex_unlock(&wled->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define WLED_AUTO_CAL_OVP_COUNT 5
|
||||
#define WLED_AUTO_CAL_CNT_DLY_US 1000000 /* 1 second */
|
||||
static bool qpnp_wled_auto_cal_required(struct qpnp_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;
|
||||
}
|
||||
|
||||
/* ovp irq handler */
|
||||
static irqreturn_t qpnp_wled_ovp_irq_handler(int irq, void *_wled)
|
||||
{
|
||||
|
@ -1114,6 +1339,21 @@ static irqreturn_t qpnp_wled_ovp_irq_handler(int irq, void *_wled)
|
|||
if (fault_sts & (QPNP_WLED_OVP_FAULT_BIT | QPNP_WLED_ILIM_FAULT_BIT))
|
||||
pr_err("WLED OVP fault detected, int_sts=%x fault_sts= %x\n",
|
||||
int_sts, fault_sts);
|
||||
|
||||
if (fault_sts & QPNP_WLED_OVP_FAULT_BIT) {
|
||||
if (wled->auto_calib_enabled && !wled->auto_calib_done) {
|
||||
if (qpnp_wled_auto_cal_required(wled)) {
|
||||
rc = wled_auto_calibrate(wled);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed auto-calibration rc=%d\n",
|
||||
rc);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
wled->auto_calib_done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -1423,7 +1663,7 @@ static int qpnp_wled_vref_config(struct qpnp_wled *wled)
|
|||
static int qpnp_wled_config(struct qpnp_wled *wled)
|
||||
{
|
||||
int rc, i, temp;
|
||||
u8 reg = 0;
|
||||
u8 reg = 0, sink_en = 0, mask;
|
||||
|
||||
/* Configure display type */
|
||||
rc = qpnp_wled_set_disp(wled, wled->ctrl_base);
|
||||
|
@ -1622,16 +1862,50 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
|
|||
rc = qpnp_wled_write_reg(wled, QPNP_WLED_CURR_SINK_REG(wled->sink_base),
|
||||
reg);
|
||||
|
||||
for (i = 0; i < wled->max_strings; i++) {
|
||||
/* SYNC DELAY */
|
||||
if (wled->sync_dly_us > QPNP_WLED_SYNC_DLY_MAX_US)
|
||||
wled->sync_dly_us = QPNP_WLED_SYNC_DLY_MAX_US;
|
||||
|
||||
reg = wled->sync_dly_us / QPNP_WLED_SYNC_DLY_STEP_US;
|
||||
mask = QPNP_WLED_SYNC_DLY_MASK;
|
||||
rc = qpnp_wled_masked_write_reg(wled,
|
||||
QPNP_WLED_SYNC_DLY_REG(wled->sink_base, i),
|
||||
mask, reg);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* FULL SCALE CURRENT */
|
||||
if (wled->fs_curr_ua > QPNP_WLED_FS_CURR_MAX_UA)
|
||||
wled->fs_curr_ua = QPNP_WLED_FS_CURR_MAX_UA;
|
||||
|
||||
reg = wled->fs_curr_ua / QPNP_WLED_FS_CURR_STEP_UA;
|
||||
mask = QPNP_WLED_FS_CURR_MASK;
|
||||
rc = qpnp_wled_masked_write_reg(wled,
|
||||
QPNP_WLED_FS_CURR_REG(wled->sink_base, i),
|
||||
mask, reg);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* CABC */
|
||||
reg = wled->en_cabc ? (1 << QPNP_WLED_CABC_SHIFT) : 0;
|
||||
mask = QPNP_WLED_CABC_MASK;
|
||||
rc = qpnp_wled_masked_write_reg(wled,
|
||||
QPNP_WLED_CABC_REG(wled->sink_base, i),
|
||||
mask, reg);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Settings specific to valid sinks */
|
||||
for (i = 0; i < wled->num_strings; i++) {
|
||||
if (wled->strings[i] >= QPNP_WLED_MAX_STRINGS) {
|
||||
if (wled->strings[i] >= wled->max_strings) {
|
||||
dev_err(&wled->pdev->dev, "Invalid string number\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* MODULATOR */
|
||||
rc = qpnp_wled_read_reg(wled,
|
||||
QPNP_WLED_MOD_EN_REG(wled->sink_base,
|
||||
wled->strings[i]), ®);
|
||||
QPNP_WLED_MOD_EN_REG(wled->sink_base, i), ®);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
reg &= QPNP_WLED_MOD_EN_MASK;
|
||||
|
@ -1643,72 +1917,22 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
|
|||
reg |= ~QPNP_WLED_GATE_DRV_MASK;
|
||||
|
||||
rc = qpnp_wled_write_reg(wled,
|
||||
QPNP_WLED_MOD_EN_REG(wled->sink_base,
|
||||
wled->strings[i]), reg);
|
||||
QPNP_WLED_MOD_EN_REG(wled->sink_base, i), reg);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* SYNC DELAY */
|
||||
if (wled->sync_dly_us > QPNP_WLED_SYNC_DLY_MAX_US)
|
||||
wled->sync_dly_us = QPNP_WLED_SYNC_DLY_MAX_US;
|
||||
|
||||
rc = qpnp_wled_read_reg(wled,
|
||||
QPNP_WLED_SYNC_DLY_REG(wled->sink_base,
|
||||
wled->strings[i]), ®);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
reg &= QPNP_WLED_SYNC_DLY_MASK;
|
||||
temp = wled->sync_dly_us / QPNP_WLED_SYNC_DLY_STEP_US;
|
||||
reg |= temp;
|
||||
rc = qpnp_wled_write_reg(wled,
|
||||
QPNP_WLED_SYNC_DLY_REG(wled->sink_base,
|
||||
wled->strings[i]), reg);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* FULL SCALE CURRENT */
|
||||
if (wled->fs_curr_ua > QPNP_WLED_FS_CURR_MAX_UA)
|
||||
wled->fs_curr_ua = QPNP_WLED_FS_CURR_MAX_UA;
|
||||
|
||||
rc = qpnp_wled_read_reg(wled,
|
||||
QPNP_WLED_FS_CURR_REG(wled->sink_base,
|
||||
wled->strings[i]), ®);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
reg &= QPNP_WLED_FS_CURR_MASK;
|
||||
temp = wled->fs_curr_ua / QPNP_WLED_FS_CURR_STEP_UA;
|
||||
reg |= temp;
|
||||
rc = qpnp_wled_write_reg(wled,
|
||||
QPNP_WLED_FS_CURR_REG(wled->sink_base,
|
||||
wled->strings[i]), reg);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* CABC */
|
||||
rc = qpnp_wled_read_reg(wled,
|
||||
QPNP_WLED_CABC_REG(wled->sink_base,
|
||||
wled->strings[i]), ®);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
reg &= QPNP_WLED_CABC_MASK;
|
||||
reg |= (wled->en_cabc << QPNP_WLED_CABC_SHIFT);
|
||||
rc = qpnp_wled_write_reg(wled,
|
||||
QPNP_WLED_CABC_REG(wled->sink_base,
|
||||
wled->strings[i]), reg);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Enable CURRENT SINK */
|
||||
rc = qpnp_wled_read_reg(wled,
|
||||
QPNP_WLED_CURR_SINK_REG(wled->sink_base), ®);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
/* SINK EN */
|
||||
temp = wled->strings[i] + QPNP_WLED_CURR_SINK_SHIFT;
|
||||
reg |= (1 << temp);
|
||||
rc = qpnp_wled_write_reg(wled,
|
||||
QPNP_WLED_CURR_SINK_REG(wled->sink_base), reg);
|
||||
if (rc)
|
||||
return rc;
|
||||
sink_en |= (1 << temp);
|
||||
}
|
||||
mask = QPNP_WLED_CURR_SINK_MASK;
|
||||
rc = qpnp_wled_masked_write_reg(wled,
|
||||
QPNP_WLED_CURR_SINK_REG(wled->sink_base),
|
||||
mask, sink_en);
|
||||
if (rc < 0) {
|
||||
dev_err(&wled->pdev->dev,
|
||||
"Failed to enable WLED sink config rc = %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = qpnp_wled_sync_reg_toggle(wled);
|
||||
|
@ -1728,8 +1952,13 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
|
|||
wled->ovp_irq, rc);
|
||||
return rc;
|
||||
}
|
||||
disable_irq(wled->ovp_irq);
|
||||
wled->ovp_irq_disabled = true;
|
||||
rc = qpnp_wled_read_reg(wled,
|
||||
QPNP_WLED_MODULE_EN_REG(wled->ctrl_base), ®);
|
||||
/* disable the OVP irq only if the module is not enabled */
|
||||
if (!rc && !(reg & QPNP_WLED_MODULE_EN_MASK)) {
|
||||
disable_irq(wled->ovp_irq);
|
||||
wled->ovp_irq_disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (wled->sc_irq >= 0) {
|
||||
|
@ -2091,11 +2320,16 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled)
|
|||
wled->en_cabc = of_property_read_bool(pdev->dev.of_node,
|
||||
"qcom,en-cabc");
|
||||
|
||||
if (wled->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE)
|
||||
wled->max_strings = QPNP_PM660_WLED_MAX_STRINGS;
|
||||
else
|
||||
wled->max_strings = QPNP_WLED_MAX_STRINGS;
|
||||
|
||||
prop = of_find_property(pdev->dev.of_node,
|
||||
"qcom,led-strings-list", &temp_val);
|
||||
if (!prop || !temp_val || temp_val > QPNP_WLED_MAX_STRINGS) {
|
||||
dev_err(&pdev->dev, "Invalid strings info, use default");
|
||||
wled->num_strings = QPNP_WLED_MAX_STRINGS;
|
||||
wled->num_strings = wled->max_strings;
|
||||
for (i = 0; i < wled->num_strings; i++)
|
||||
wled->strings[i] = i;
|
||||
} else {
|
||||
|
@ -2118,6 +2352,9 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled)
|
|||
|
||||
wled->lcd_psm_ctrl = of_property_read_bool(pdev->dev.of_node,
|
||||
"qcom,lcd-psm-ctrl");
|
||||
|
||||
wled->auto_calib_enabled = of_property_read_bool(pdev->dev.of_node,
|
||||
"qcom,auto-calibration-enable");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2185,13 +2422,13 @@ static int qpnp_wled_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
mutex_init(&wled->bus_lock);
|
||||
mutex_init(&wled->lock);
|
||||
rc = qpnp_wled_config(wled);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "wled config failed\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
mutex_init(&wled->lock);
|
||||
INIT_WORK(&wled->work, qpnp_wled_work);
|
||||
wled->ramp_ms = QPNP_WLED_RAMP_DLY_MS;
|
||||
wled->ramp_step = 1;
|
||||
|
|
Loading…
Add table
Reference in a new issue