/* sysfs store function for full scale current in ua*/ 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; u8 reg; if (sscanf(buf, "%d", &data) != 1) return -EINVAL; for (i = 0; i < wled->num_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])); 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])); if (rc) return rc; } wled->fs_curr_ua = data; return count; }
static int qpnp_wled_set_scale(struct qpnp_wled *wled) { u8 reg = 0; int rc, curr; wled->curr_scale = QPNP_WLED_CURR_SCALE_MAX; rc = qpnp_wled_read_reg(wled, ®, QPNP_WLED_FS_CURR_REG(wled->sink_base, wled->strings[0])); if (rc) return rc; reg &= ~QPNP_WLED_FS_CURR_MASK; curr = (reg * QPNP_WLED_FS_CURR_STEP_UA); if (curr > wled->fs_curr_ua) wled->curr_scale = (wled->fs_curr_ua * QPNP_WLED_CURR_SCALE_MAX) / curr; pr_debug("%s: curr=%d fs_curr_ua=%d curr_scale=%d\n", __func__, curr, wled->fs_curr_ua, wled->curr_scale); return 0; }
/* Configure WLED registers */ static int qpnp_wled_config(struct qpnp_wled *wled) { int rc, i, temp; u8 reg = 0; /* Configure display type */ rc = qpnp_wled_set_disp(wled, wled->ctrl_base); if (rc < 0) return rc; /* Configure the FEEDBACK OUTPUT register */ rc = qpnp_wled_read_reg(wled, ®, QPNP_WLED_FDBK_OP_REG(wled->ctrl_base)); if (rc < 0) return rc; reg &= QPNP_WLED_FDBK_OP_MASK; reg |= wled->fdbk_op; rc = qpnp_wled_write_reg(wled, ®, QPNP_WLED_FDBK_OP_REG(wled->ctrl_base)); if (rc) return rc; /* Configure the VREF register */ if (wled->vref_mv < QPNP_WLED_VREF_MIN_MV) wled->vref_mv = QPNP_WLED_VREF_MIN_MV; else if (wled->vref_mv > QPNP_WLED_VREF_MAX_MV) wled->vref_mv = QPNP_WLED_VREF_MAX_MV; rc = qpnp_wled_read_reg(wled, ®, QPNP_WLED_VREF_REG(wled->ctrl_base)); if (rc < 0) return rc; reg &= QPNP_WLED_VREF_MASK; temp = wled->vref_mv - QPNP_WLED_VREF_MIN_MV; reg |= (temp / QPNP_WLED_VREF_STEP_MV); rc = qpnp_wled_write_reg(wled, ®, QPNP_WLED_VREF_REG(wled->ctrl_base)); if (rc) return rc; /* Configure the ILIM register */ if (wled->ilim_ma < QPNP_WLED_ILIM_MIN_MA) wled->ilim_ma = QPNP_WLED_ILIM_MIN_MA; else if (wled->ilim_ma > QPNP_WLED_ILIM_MAX_MA) wled->ilim_ma = QPNP_WLED_ILIM_MAX_MA; rc = qpnp_wled_read_reg(wled, ®, QPNP_WLED_ILIM_REG(wled->ctrl_base)); if (rc < 0) return rc; reg &= QPNP_WLED_ILIM_MASK; reg |= (wled->ilim_ma / QPNP_WLED_ILIM_STEP_MA); rc = qpnp_wled_write_reg(wled, ®, QPNP_WLED_ILIM_REG(wled->ctrl_base)); if (rc) return rc; /* Configure the MAX BOOST DUTY register */ if (wled->boost_duty_ns < QPNP_WLED_BOOST_DUTY_MIN_NS) wled->boost_duty_ns = QPNP_WLED_BOOST_DUTY_MIN_NS; else if (wled->boost_duty_ns > QPNP_WLED_BOOST_DUTY_MAX_NS) wled->boost_duty_ns = QPNP_WLED_BOOST_DUTY_MAX_NS; rc = qpnp_wled_read_reg(wled, ®, QPNP_WLED_BOOST_DUTY_REG(wled->ctrl_base)); if (rc < 0) return rc; reg &= QPNP_WLED_BOOST_DUTY_MASK; reg |= (wled->boost_duty_ns / QPNP_WLED_BOOST_DUTY_STEP_NS); rc = qpnp_wled_write_reg(wled, ®, QPNP_WLED_BOOST_DUTY_REG(wled->ctrl_base)); if (rc) return rc; /* Configure the SWITCHING FREQ register */ if (wled->switch_freq_khz == QPNP_WLED_SWITCH_FREQ_1600_KHZ) temp = QPNP_WLED_SWITCH_FREQ_1600_KHZ_CODE; else temp = QPNP_WLED_SWITCH_FREQ_800_KHZ_CODE; rc = qpnp_wled_read_reg(wled, ®, QPNP_WLED_SWITCH_FREQ_REG(wled->ctrl_base)); if (rc < 0) return rc; reg &= QPNP_WLED_SWITCH_FREQ_MASK; reg |= temp; rc = qpnp_wled_write_reg(wled, ®, QPNP_WLED_SWITCH_FREQ_REG(wled->ctrl_base)); if (rc) return rc; /* Configure the OVP register */ if (wled->ovp_mv <= QPNP_WLED_OVP_17800_MV) { wled->ovp_mv = QPNP_WLED_OVP_17800_MV; temp = 3; } else if (wled->ovp_mv <= QPNP_WLED_OVP_19400_MV) { wled->ovp_mv = QPNP_WLED_OVP_19400_MV; temp = 2; } else if (wled->ovp_mv <= QPNP_WLED_OVP_29500_MV) { wled->ovp_mv = QPNP_WLED_OVP_29500_MV; temp = 1; } else { wled->ovp_mv = QPNP_WLED_OVP_31000_MV; temp = 0; } rc = qpnp_wled_read_reg(wled, ®, QPNP_WLED_OVP_REG(wled->ctrl_base)); if (rc < 0) return rc; reg &= QPNP_WLED_OVP_MASK; reg |= temp; rc = qpnp_wled_write_reg(wled, ®, QPNP_WLED_OVP_REG(wled->ctrl_base)); if (rc) return rc; /* Configure the MODULATION register */ if (wled->mod_freq_khz <= QPNP_WLED_MOD_FREQ_1200_KHZ) { wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_1200_KHZ; temp = 3; } else if (wled->mod_freq_khz <= QPNP_WLED_MOD_FREQ_2400_KHZ) { wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_2400_KHZ; temp = 2; } else if (wled->mod_freq_khz <= QPNP_WLED_MOD_FREQ_9600_KHZ) { wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_9600_KHZ; temp = 1; } else if (wled->mod_freq_khz <= QPNP_WLED_MOD_FREQ_19200_KHZ) { wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_19200_KHZ; temp = 0; } else { wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_9600_KHZ; temp = 1; } rc = qpnp_wled_read_reg(wled, ®, QPNP_WLED_MOD_REG(wled->sink_base)); if (rc < 0) return rc; reg &= QPNP_WLED_MOD_FREQ_MASK; reg |= (temp << QPNP_WLED_MOD_FREQ_SHIFT); reg &= QPNP_WLED_PHASE_STAG_MASK; reg |= (wled->en_phase_stag << QPNP_WLED_PHASE_STAG_SHIFT); reg &= QPNP_WLED_ACC_CLK_FREQ_MASK; reg |= (temp << QPNP_WLED_ACC_CLK_FREQ_SHIFT); reg &= QPNP_WLED_DIM_RES_MASK; reg |= (wled->en_9b_dim_res << QPNP_WLED_DIM_RES_SHIFT); if (wled->dim_mode == QPNP_WLED_DIM_HYBRID) { reg &= QPNP_WLED_DIM_HYB_MASK; reg |= (1 << QPNP_WLED_DIM_HYB_SHIFT); } else { reg &= QPNP_WLED_DIM_HYB_MASK; reg |= (0 << QPNP_WLED_DIM_HYB_SHIFT); reg &= QPNP_WLED_DIM_ANA_MASK; reg |= wled->dim_mode; } rc = qpnp_wled_write_reg(wled, ®, QPNP_WLED_MOD_REG(wled->sink_base)); if (rc) return rc; /* Configure the HYBRID THRESHOLD register */ if (wled->hyb_thres < QPNP_WLED_HYB_THRES_MIN) wled->hyb_thres = QPNP_WLED_HYB_THRES_MIN; else if (wled->hyb_thres > QPNP_WLED_HYB_THRES_MAX) wled->hyb_thres = QPNP_WLED_HYB_THRES_MAX; rc = qpnp_wled_read_reg(wled, ®, QPNP_WLED_HYB_THRES_REG(wled->sink_base)); if (rc < 0) return rc; reg &= QPNP_WLED_HYB_THRES_MASK; temp = fls(wled->hyb_thres / QPNP_WLED_HYB_THRES_MIN) - 1; reg |= temp; rc = qpnp_wled_write_reg(wled, ®, QPNP_WLED_HYB_THRES_REG(wled->sink_base)); if (rc) return rc; /* Configure TEST5 register */ if (wled->dim_mode == QPNP_WLED_DIM_DIGITAL) reg = QPNP_WLED_SINK_TEST5_DIG; else reg = QPNP_WLED_SINK_TEST5_HYB; rc = qpnp_wled_sec_access(wled, wled->sink_base); if (rc) return rc; rc = qpnp_wled_write_reg(wled, ®, QPNP_WLED_SINK_TEST5_REG(wled->sink_base)); if (rc) return rc; /* disable all current sinks and enable selected strings */ reg = 0x00; rc = qpnp_wled_write_reg(wled, ®, QPNP_WLED_CURR_SINK_REG(wled->sink_base)); for (i = 0; i < wled->num_strings; i++) { if (wled->strings[i] >= QPNP_WLED_MAX_STRINGS) { dev_err(&wled->spmi->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])); if (rc < 0) return rc; reg &= QPNP_WLED_MOD_EN_MASK; reg |= (QPNP_WLED_MOD_EN << QPNP_WLED_MOD_EN_SHFT); 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, wled->strings[i])); if (rc) return rc; /* SYNC DELAY */ if (wled->sync_dly_us < QPNP_WLED_SYNC_DLY_MIN_US) wled->sync_dly_us = QPNP_WLED_SYNC_DLY_MIN_US; else 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])); if (rc) return rc; /* FULL SCALE CURRENT */ if (wled->fs_curr_ua < QPNP_WLED_FS_CURR_MIN_UA) wled->fs_curr_ua = QPNP_WLED_FS_CURR_MIN_UA; else 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])); 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])); 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; 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)); if (rc) return rc; } /* LAB fast precharge */ rc = qpnp_wled_read_reg(wled, ®, QPNP_WLED_LAB_FAST_PC_REG(wled->lab_base)); if (rc < 0) return rc; reg &= QPNP_WLED_LAB_FAST_PC_MASK; reg |= (wled->lab_fast_precharge << QPNP_WLED_LAB_FAST_PC_SHIFT); rc = qpnp_wled_write_reg(wled, ®, QPNP_WLED_LAB_FAST_PC_REG(wled->lab_base)); if (rc) return rc; /* Configure lab display type */ rc = qpnp_wled_set_disp(wled, wled->lab_base); if (rc < 0) return rc; /* make LAB module ready */ rc = qpnp_wled_mod_rdy(wled, wled->lab_base, true); if (rc < 0) return rc; /* IBB active bias */ if (wled->ibb_pwrup_dly_ms < QPNP_WLED_IBB_PWRUP_DLY_MIN_MS) wled->ibb_pwrup_dly_ms = QPNP_WLED_IBB_PWRUP_DLY_MIN_MS; else if (wled->ibb_pwrup_dly_ms > QPNP_WLED_IBB_PWRUP_DLY_MAX_MS) wled->ibb_pwrup_dly_ms = QPNP_WLED_IBB_PWRUP_DLY_MAX_MS; rc = qpnp_wled_read_reg(wled, ®, QPNP_WLED_IBB_BIAS_REG(wled->ibb_base)); if (rc < 0) return rc; reg &= QPNP_WLED_IBB_BIAS_MASK; reg |= (!wled->ibb_bias_active << QPNP_WLED_IBB_BIAS_SHIFT); temp = fls(wled->ibb_pwrup_dly_ms) - 1; reg &= QPNP_WLED_IBB_PWRUP_DLY_MASK; reg |= (temp << QPNP_WLED_IBB_PWRUP_DLY_SHIFT); rc = qpnp_wled_sec_access(wled, wled->ibb_base); if (rc) return rc; rc = qpnp_wled_write_reg(wled, ®, QPNP_WLED_IBB_BIAS_REG(wled->ibb_base)); if (rc) return rc; /* Configure ibb display type */ rc = qpnp_wled_set_disp(wled, wled->ibb_base); if (rc < 0) return rc; /* make IBB module ready */ rc = qpnp_wled_mod_rdy(wled, wled->ibb_base, true); if (rc < 0) return rc; /* setup ovp and sc irqs */ if (wled->ovp_irq >= 0) { rc = devm_request_threaded_irq(&wled->spmi->dev, wled->ovp_irq, NULL, qpnp_wled_ovp_irq, QPNP_IRQ_FLAGS, "qpnp_wled_ovp_irq", wled); if (rc < 0) { dev_err(&wled->spmi->dev, "Unable to request ovp(%d) IRQ(err:%d)\n", wled->ovp_irq, rc); return rc; } } if (wled->sc_irq >= 0) { wled->sc_cnt = 0; rc = devm_request_threaded_irq(&wled->spmi->dev, wled->sc_irq, NULL, qpnp_wled_sc_irq, QPNP_IRQ_FLAGS, "qpnp_wled_sc_irq", wled); if (rc < 0) { dev_err(&wled->spmi->dev, "Unable to request sc(%d) IRQ(err:%d)\n", wled->sc_irq, rc); return rc; } rc = qpnp_wled_read_reg(wled, ®, QPNP_WLED_SC_PRO_REG(wled->ctrl_base)); if (rc < 0) return rc; reg &= QPNP_WLED_EN_SC_MASK; reg |= 1 << QPNP_WLED_EN_SC_SHIFT; rc = qpnp_wled_write_reg(wled, ®, QPNP_WLED_SC_PRO_REG(wled->ctrl_base)); if (rc) return rc; if (wled->en_ext_pfet_sc_pro) { rc = qpnp_wled_sec_access(wled, wled->ctrl_base); if (rc) return rc; reg = QPNP_WLED_EXT_FET_DTEST2; rc = qpnp_wled_write_reg(wled, ®, QPNP_WLED_TEST_REG(wled->ctrl_base)); if (rc) return rc; } } return 0; }
/* Configure WLED registers */ static int qpnp_wled_config(struct qpnp_wled *wled) { int rc, i, temp; uint8_t reg = 0; /* Configure display type */ rc = qpnp_wled_set_display_type(wled, wled->ctrl_base); if (rc < 0) return rc; /* Recommended WLED MDOS settings for AMOLED */ if (wled->disp_type_amoled) { pm8x41_wled_reg_write(QPNP_WLED_VLOOP_COMP_RES(wled->ctrl_base), 0x8F); pm8x41_wled_reg_write(QPNP_WLED_VLOOP_COMP_GM(wled->ctrl_base), 0x81); pm8x41_wled_reg_write(QPNP_WLED_PSM_CTRL(wled->ctrl_base), 0x83); rc = qpnp_wled_sec_access(wled, wled->ctrl_base); if (rc) return rc; pm8x41_wled_reg_write(QPNP_WLED_TEST4(wled->ctrl_base), 0x13); } /* Configure the FEEDBACK OUTPUT register */ reg = pm8x41_wled_reg_read( QPNP_WLED_FDBK_OP_REG(wled->ctrl_base)); reg &= QPNP_WLED_FDBK_OP_MASK; reg |= wled->fdbk_op; pm8x41_wled_reg_write(QPNP_WLED_FDBK_OP_REG(wled->ctrl_base), reg); /* Configure the VREF register */ if (wled->vref_mv < QPNP_WLED_VREF_MIN_MV) wled->vref_mv = QPNP_WLED_VREF_MIN_MV; else if (wled->vref_mv > QPNP_WLED_VREF_MAX_MV) wled->vref_mv = QPNP_WLED_VREF_MAX_MV; reg = pm8x41_wled_reg_read( QPNP_WLED_VREF_REG(wled->ctrl_base)); reg &= QPNP_WLED_VREF_MASK; temp = wled->vref_mv - QPNP_WLED_VREF_MIN_MV; reg |= (temp / QPNP_WLED_VREF_STEP_MV); pm8x41_wled_reg_write(QPNP_WLED_VREF_REG(wled->ctrl_base), reg); /* Configure the ILIM register */ if (wled->ilim_ma < QPNP_WLED_ILIM_MIN_MA) wled->ilim_ma = QPNP_WLED_ILIM_MIN_MA; else if (wled->ilim_ma > QPNP_WLED_ILIM_MAX_MA) wled->ilim_ma = QPNP_WLED_ILIM_MAX_MA; reg = pm8x41_wled_reg_read( QPNP_WLED_ILIM_REG(wled->ctrl_base)); temp = (wled->ilim_ma / QPNP_WLED_ILIM_STEP_MA); if (temp != (reg & ~QPNP_WLED_ILIM_MASK)) { reg &= QPNP_WLED_ILIM_MASK; reg |= temp; reg |= QPNP_WLED_ILIM_OVERWRITE; pm8x41_wled_reg_write(QPNP_WLED_ILIM_REG(wled->ctrl_base), reg); } /* Configure the MAX BOOST DUTY register */ if (wled->boost_duty_ns < QPNP_WLED_BOOST_DUTY_MIN_NS) wled->boost_duty_ns = QPNP_WLED_BOOST_DUTY_MIN_NS; else if (wled->boost_duty_ns > QPNP_WLED_BOOST_DUTY_MAX_NS) wled->boost_duty_ns = QPNP_WLED_BOOST_DUTY_MAX_NS; reg = pm8x41_wled_reg_read( QPNP_WLED_BOOST_DUTY_REG(wled->ctrl_base)); reg &= QPNP_WLED_BOOST_DUTY_MASK; reg |= (wled->boost_duty_ns / QPNP_WLED_BOOST_DUTY_STEP_NS); pm8x41_wled_reg_write(QPNP_WLED_BOOST_DUTY_REG(wled->ctrl_base), reg); /* Configure the SWITCHING FREQ register */ if (wled->switch_freq_khz == QPNP_WLED_SWITCH_FREQ_1600_KHZ) temp = QPNP_WLED_SWITCH_FREQ_1600_KHZ_CODE; else temp = QPNP_WLED_SWITCH_FREQ_800_KHZ_CODE; reg = pm8x41_wled_reg_read( QPNP_WLED_SWITCH_FREQ_REG(wled->ctrl_base)); reg &= QPNP_WLED_SWITCH_FREQ_MASK; reg |= temp; pm8x41_wled_reg_write(QPNP_WLED_SWITCH_FREQ_REG(wled->ctrl_base), reg); /* Configure the OVP register */ if (wled->ovp_mv <= QPNP_WLED_OVP_17800_MV) { wled->ovp_mv = QPNP_WLED_OVP_17800_MV; temp = 3; } else if (wled->ovp_mv <= QPNP_WLED_OVP_19400_MV) { wled->ovp_mv = QPNP_WLED_OVP_19400_MV; temp = 2; } else if (wled->ovp_mv <= QPNP_WLED_OVP_29500_MV) { wled->ovp_mv = QPNP_WLED_OVP_29500_MV; temp = 1; } else { wled->ovp_mv = QPNP_WLED_OVP_31000_MV; temp = 0; } reg = pm8x41_wled_reg_read( QPNP_WLED_OVP_REG(wled->ctrl_base)); reg &= QPNP_WLED_OVP_MASK; reg |= temp; pm8x41_wled_reg_write(QPNP_WLED_OVP_REG(wled->ctrl_base), reg); /* Configure the MODULATION register */ if (wled->mod_freq_khz <= QPNP_WLED_MOD_FREQ_1200_KHZ) { wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_1200_KHZ; temp = 3; } else if (wled->mod_freq_khz <= QPNP_WLED_MOD_FREQ_2400_KHZ) { wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_2400_KHZ; temp = 2; } else if (wled->mod_freq_khz <= QPNP_WLED_MOD_FREQ_9600_KHZ) { wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_9600_KHZ; temp = 1; } else { wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_19200_KHZ; temp = 0; } reg = pm8x41_wled_reg_read(QPNP_WLED_MOD_REG(wled->sink_base)); reg &= QPNP_WLED_MOD_FREQ_MASK; reg |= (temp << QPNP_WLED_MOD_FREQ_SHIFT); reg &= QPNP_WLED_PHASE_STAG_MASK; reg |= (wled->en_phase_stag << QPNP_WLED_PHASE_STAG_SHIFT); reg &= QPNP_WLED_DIM_RES_MASK; reg |= (wled->en_9b_dim_res << QPNP_WLED_DIM_RES_SHIFT); if (wled->dim_mode == QPNP_WLED_DIM_HYBRID) { reg &= QPNP_WLED_DIM_HYB_MASK; reg |= (1 << QPNP_WLED_DIM_HYB_SHIFT); } else { reg &= QPNP_WLED_DIM_HYB_MASK; reg |= (0 << QPNP_WLED_DIM_HYB_SHIFT); reg &= QPNP_WLED_DIM_ANA_MASK; reg |= wled->dim_mode; } pm8x41_wled_reg_write(QPNP_WLED_MOD_REG(wled->sink_base), reg); /* Configure the HYBRID THRESHOLD register */ if (wled->hyb_thres < QPNP_WLED_HYB_THRES_MIN) wled->hyb_thres = QPNP_WLED_HYB_THRES_MIN; else if (wled->hyb_thres > QPNP_WLED_HYB_THRES_MAX) wled->hyb_thres = QPNP_WLED_HYB_THRES_MAX; reg = pm8x41_wled_reg_read( QPNP_WLED_HYB_THRES_REG(wled->sink_base)); reg &= QPNP_WLED_HYB_THRES_MASK; temp = fls(wled->hyb_thres / QPNP_WLED_HYB_THRES_MIN) - 1; reg |= temp; pm8x41_wled_reg_write(QPNP_WLED_HYB_THRES_REG(wled->sink_base), reg); for (i = 0; i < wled->num_strings; i++) { if (wled->strings[i] >= QPNP_WLED_MAX_STRINGS) { dprintf(CRITICAL,"Invalid string number\n"); return ERR_NOT_VALID; } /* MODULATOR */ reg = pm8x41_wled_reg_read( QPNP_WLED_MOD_EN_REG(wled->sink_base, wled->strings[i])); reg &= QPNP_WLED_MOD_EN_MASK; reg |= (QPNP_WLED_MOD_EN << QPNP_WLED_MOD_EN_SHFT); pm8x41_wled_reg_write(QPNP_WLED_MOD_EN_REG(wled->sink_base, wled->strings[i]), reg); /* SYNC DELAY */ if (wled->sync_dly_us > QPNP_WLED_SYNC_DLY_MAX_US) wled->sync_dly_us = QPNP_WLED_SYNC_DLY_MAX_US; reg = pm8x41_wled_reg_read( QPNP_WLED_SYNC_DLY_REG(wled->sink_base, wled->strings[i])); reg &= QPNP_WLED_SYNC_DLY_MASK; temp = wled->sync_dly_us / QPNP_WLED_SYNC_DLY_STEP_US; reg |= temp; pm8x41_wled_reg_write(QPNP_WLED_SYNC_DLY_REG(wled->sink_base, wled->strings[i]), reg); /* 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 = pm8x41_wled_reg_read( QPNP_WLED_FS_CURR_REG(wled->sink_base, wled->strings[i])); reg &= QPNP_WLED_FS_CURR_MASK; temp = wled->fs_curr_ua / QPNP_WLED_FS_CURR_STEP_UA; reg |= temp; pm8x41_wled_reg_write(QPNP_WLED_FS_CURR_REG(wled->sink_base, wled->strings[i]), reg); /* CABC */ reg = pm8x41_wled_reg_read( QPNP_WLED_CABC_REG(wled->sink_base, wled->strings[i])); reg &= QPNP_WLED_CABC_MASK; reg |= (wled->en_cabc << QPNP_WLED_CABC_SHIFT); pm8x41_wled_reg_write(QPNP_WLED_CABC_REG(wled->sink_base, wled->strings[i]), reg); /* Enable CURRENT SINK */ reg = pm8x41_wled_reg_read( QPNP_WLED_CURR_SINK_REG(wled->sink_base)); temp = wled->strings[i] + QPNP_WLED_CURR_SINK_SHIFT; reg |= (1 << temp); pm8x41_wled_reg_write(QPNP_WLED_CURR_SINK_REG(wled->sink_base), reg); } /* LAB fast precharge */ reg = pm8x41_wled_reg_read( QPNP_WLED_LAB_FAST_PC_REG(wled->lab_base)); reg &= QPNP_WLED_LAB_FAST_PC_MASK; reg |= (wled->lab_fast_precharge << QPNP_WLED_LAB_FAST_PC_SHIFT); pm8x41_wled_reg_write(QPNP_WLED_LAB_FAST_PC_REG(wled->lab_base), reg); /* Configure lab display type */ rc = qpnp_wled_set_display_type(wled, wled->lab_base); if (rc < 0) return rc; /* make LAB module ready */ rc = qpnp_wled_module_ready(wled, wled->lab_base, true); if (rc < 0) return rc; /* Disable LAB pulse skipping for AMOLED */ if (wled->disp_type_amoled) pm8x41_wled_reg_write(wled->lab_base + QPNP_LABIBB_PS_CTL, 0x00); /* IBB active bias */ if (wled->ibb_pwrup_dly_ms > QPNP_WLED_IBB_PWRUP_DLY_MAX_MS) wled->ibb_pwrup_dly_ms = QPNP_WLED_IBB_PWRUP_DLY_MAX_MS; if (wled->ibb_pwrdn_dly_ms > QPNP_WLED_IBB_PWRDN_DLY_MAX_MS) wled->ibb_pwrdn_dly_ms = QPNP_WLED_IBB_PWRDN_DLY_MAX_MS; reg = pm8x41_wled_reg_read( QPNP_WLED_IBB_BIAS_REG(wled->ibb_base)); reg &= QPNP_WLED_IBB_BIAS_MASK; reg |= (!wled->ibb_bias_active << QPNP_WLED_IBB_BIAS_SHIFT); temp = wled->ibb_pwrup_dly_ms; reg &= QPNP_WLED_IBB_PWRUP_DLY_MASK; reg |= (temp << QPNP_WLED_IBB_PWRUP_DLY_SHIFT); /* Power down delay bits could already be set, clear them before * or'ing new values */ reg &= ~(PWRDN_DLY2_MASK); reg |= wled->ibb_pwrdn_dly_ms; reg |= (wled->ibb_discharge_en << 2); rc = qpnp_wled_sec_access(wled, wled->ibb_base); if (rc) return rc; pm8x41_wled_reg_write(QPNP_WLED_IBB_BIAS_REG(wled->ibb_base), reg); /* Configure ibb display type */ rc = qpnp_wled_set_display_type(wled, wled->ibb_base); if (rc < 0) return rc; /* make IBB module ready */ rc = qpnp_wled_module_ready(wled, wled->ibb_base, true); if (rc < 0) return rc; rc = qpnp_labibb_regulator_set_voltage(wled); if (rc < 0) return rc; return 0; }