Merge "backlight: qcom-spmi-wled: Add support to configure slew ramp time"

This commit is contained in:
qctecmdr 2024-05-25 02:16:54 -07:00 committed by Gerrit - the friendly Code Review server
commit 6d9f7d36ab

View file

@ -181,6 +181,22 @@
#define WLED5_SINK_FLASH_SHDN_CLR_REG 0xb6
#define WLED5_SINK_BRIGHTNESS_SLEW_RATE_CTL_REG 0xb8
#define WLED5_EN_SLEW_CTL BIT(7)
#define WLED5_EN_EXP_LUT BIT(6)
#define WLED5_SLEW_RAMP_TIME_SEL GENMASK(3, 0)
#define WLED5_SINK_DIMMING_EXP_LUT0_LSB_REG 0xc0
#define WLED5_SINK_DIMMING_EXP_LUT0_MSB_REG 0xc1
#define WLED5_SINK_DIMMING_EXP_LUT1_LSB_REG 0xc2
#define WLED5_SINK_DIMMING_EXP_LUT1_MSB_REG 0xc3
#define WLED5_SINK_DIMMING_EXP_LUT_LSB_MASK GENMASK(7, 0)
#define WLED5_SINK_DIMMING_EXP_LUT_MSB_MASK GENMASK(6, 0)
#define WLED5_SINK_EXP_LUT_INDEX_REG 0xc9
#define EXP_DIMMING_TABLE_SIZE 256
enum wled_version {
WLED_PMI8998 = 4,
WLED_PM660L,
@ -209,9 +225,11 @@ struct wled_config {
int string_cfg;
int mod_sel;
int cabc_sel;
int slew_ramp_time;
bool en_cabc;
bool ext_pfet_sc_pro_en;
bool auto_calib_enabled;
bool use_exp_dimming;
};
struct wled_flash_config {
@ -259,6 +277,7 @@ struct wled {
enum wled_flash_mode flash_mode;
u8 num_strings;
u32 leds_per_string;
u32 exp_map[EXP_DIMMING_TABLE_SIZE];
};
enum wled5_mod_sel {
@ -508,6 +527,16 @@ static int wled_set_brightness(struct wled *wled, u16 brightness)
return 0;
}
static bool wled_exp_dimming_supported(struct wled *wled)
{
if (*wled->version == WLED_PM7325B)
return true;
dev_dbg(&wled->pdev->dev, "Exponential dimming not supported for WLED version %d\n",
*wled->version);
return false;
}
static int wled_update_status(struct backlight_device *bl)
{
struct wled *wled = bl_get_data(bl);
@ -542,6 +571,17 @@ static int wled_update_status(struct backlight_device *bl)
pr_err("wled enable failed rc:%d\n", rc);
goto unlock_mutex;
}
if (wled_exp_dimming_supported(wled)) {
rc = regmap_update_bits(wled->regmap,
wled->sink_addr + WLED5_SINK_BRIGHTNESS_SLEW_RATE_CTL_REG,
WLED5_SLEW_RAMP_TIME_SEL,
wled->cfg.slew_ramp_time);
if (rc < 0) {
pr_err("Failed to write to SLEW_RATE_REGISTER rc:%d\n", rc);
goto unlock_mutex;
}
}
}
if (is_wled5(wled)) {
@ -553,6 +593,16 @@ static int wled_update_status(struct backlight_device *bl)
}
}
} else {
if (wled_exp_dimming_supported(wled)) {
rc = regmap_update_bits(wled->regmap,
wled->sink_addr + WLED5_SINK_BRIGHTNESS_SLEW_RATE_CTL_REG,
WLED5_SLEW_RAMP_TIME_SEL, 0);
if (rc < 0) {
pr_err("Failed to write to SLEW_RATE_REGISTER rc:%d\n", rc);
goto unlock_mutex;
}
}
rc = wled_module_enable(wled, brightness);
if (rc < 0) {
pr_err("wled disable failed rc:%d\n", rc);
@ -1117,6 +1167,77 @@ static inline u8 get_wled_safety_time(int time_ms)
return 0;
}
static int wled_read_exp_dimming_map(struct device_node *node, struct wled *wled)
{
int rc, len;
if (!wled_exp_dimming_supported(wled))
return 0;
len = of_property_count_elems_of_size(node, "qcom,exp-dimming-map", sizeof(u32));
if (len != EXP_DIMMING_TABLE_SIZE) {
dev_err(&wled->pdev->dev, "Invalid exponential map length: %d, must be %d bytes length\n",
len, EXP_DIMMING_TABLE_SIZE);
return -EINVAL;
}
rc = of_property_read_u32_array(node, "qcom,exp-dimming-map",
wled->exp_map, EXP_DIMMING_TABLE_SIZE);
if (rc < 0)
dev_err(&wled->pdev->dev, "Error in reading qcom,exp-dimming-map, rc=%d\n",
rc);
return rc;
}
static int wled_program_exp_dimming(struct wled *wled)
{
int rc, i;
u8 val[4];
if (!wled_exp_dimming_supported(wled))
return 0;
rc = wled_module_enable(wled, 0);
if (rc < 0) {
dev_err(&wled->pdev->dev, "wled disable failed rc:%d\n", rc);
return rc;
}
rc = regmap_update_bits(wled->regmap,
wled->sink_addr + WLED5_SINK_BRIGHTNESS_SLEW_RATE_CTL_REG,
WLED5_EN_EXP_LUT, WLED5_EN_EXP_LUT);
if (rc < 0)
goto wled_enable;
for (i = 0; i < EXP_DIMMING_TABLE_SIZE / 2; i++) {
val[0] = wled->exp_map[2 * i] & WLED5_SINK_DIMMING_EXP_LUT_LSB_MASK;
val[1] = (wled->exp_map[2 * i] >> 8) & WLED5_SINK_DIMMING_EXP_LUT_MSB_MASK;
val[2] = wled->exp_map[2 * i + 1] & WLED5_SINK_DIMMING_EXP_LUT_LSB_MASK;
val[3] = (wled->exp_map[2 * i + 1] >> 8) & WLED5_SINK_DIMMING_EXP_LUT_MSB_MASK;
rc = regmap_write(wled->regmap, wled->sink_addr + WLED5_SINK_EXP_LUT_INDEX_REG, i);
if (rc < 0)
goto exp_dimm_fail;
rc = regmap_bulk_write(wled->regmap,
wled->sink_addr + WLED5_SINK_DIMMING_EXP_LUT0_LSB_REG,
val, sizeof(val));
if (rc < 0)
goto exp_dimm_fail;
}
wled_module_enable(wled, 1);
return rc;
exp_dimm_fail:
rc = regmap_update_bits(wled->regmap,
wled->sink_addr + WLED5_SINK_BRIGHTNESS_SLEW_RATE_CTL_REG,
WLED5_EN_EXP_LUT, 0);
wled_enable:
wled_module_enable(wled, 1);
return rc;
}
static int wled5_setup(struct wled *wled)
{
int rc, temp, i;
@ -1217,6 +1338,26 @@ static int wled5_setup(struct wled *wled)
if (rc < 0)
return rc;
if (wled_exp_dimming_supported(wled)) {
val = WLED5_EN_SLEW_CTL | wled->cfg.slew_ramp_time;
rc = regmap_update_bits(wled->regmap,
wled->sink_addr +
WLED5_SINK_BRIGHTNESS_SLEW_RATE_CTL_REG,
WLED5_EN_SLEW_CTL | WLED5_SLEW_RAMP_TIME_SEL,
val);
if (rc < 0)
return rc;
}
if (wled->cfg.use_exp_dimming) {
rc = wled_program_exp_dimming(wled);
if (rc < 0) {
dev_err(&wled->pdev->dev, "Programming exponential dimming map failed, rc=%d\n",
rc);
return rc;
}
}
if (wled->ovp_irq >= 0) {
rc = devm_request_threaded_irq(&wled->pdev->dev, wled->ovp_irq,
NULL, wled_ovp_irq_handler, IRQF_ONESHOT,
@ -1389,6 +1530,7 @@ static const struct wled_config wled4_config_defaults = {
.string_cfg = 0xf,
.mod_sel = -EINVAL,
.cabc_sel = -EINVAL,
.slew_ramp_time = -EINVAL,
.en_cabc = 0,
.ext_pfet_sc_pro_en = 0,
.auto_calib_enabled = 0,
@ -1402,6 +1544,7 @@ static const struct wled_config wled5_config_defaults = {
.string_cfg = 0xf,
.mod_sel = 0,
.cabc_sel = 0,
.slew_ramp_time = 6, /* 256 ms */
.en_cabc = 0,
.ext_pfet_sc_pro_en = 0,
.auto_calib_enabled = 0,
@ -1488,6 +1631,17 @@ static const struct wled_var_cfg wled5_cabc_sel_cfg = {
.size = 4,
};
/* Applicable only for PM7325B */
static const u32 wled5_slew_ramp_time_values[] = {
2, 4, 8, 64, 128, 192, 256, 320, 384, 448, 512, 704,
896, 1024, 2048, 4096,
};
static const struct wled_var_cfg wled5_slew_ramp_time_cfg = {
.values = wled5_slew_ramp_time_values,
.size = ARRAY_SIZE(wled5_slew_ramp_time_values),
};
static u32 wled_values(const struct wled_var_cfg *cfg, u32 idx)
{
if (!cfg)
@ -2261,6 +2415,11 @@ static int wled_configure(struct wled *wled, struct device *dev)
.val_ptr = &cfg->cabc_sel,
.cfg = &wled5_cabc_sel_cfg,
},
{
.name = "qcom,slew-ramp-time",
.val_ptr = &cfg->slew_ramp_time,
.cfg = &wled5_slew_ramp_time_cfg,
},
};
const struct {
@ -2270,6 +2429,7 @@ static int wled_configure(struct wled *wled, struct device *dev)
{ "qcom,en-cabc", &cfg->en_cabc, },
{ "qcom,ext-pfet-sc-pro", &cfg->ext_pfet_sc_pro_en, },
{ "qcom,auto-calibration", &cfg->auto_calib_enabled, },
{ "qcom,use-exp-dimming", &cfg->use_exp_dimming, },
};
prop_addr = of_get_address(dev->of_node, 0, NULL, NULL);
@ -2342,6 +2502,15 @@ static int wled_configure(struct wled *wled, struct device *dev)
*bool_opts[i].val_ptr = true;
}
if (wled->cfg.use_exp_dimming) {
rc = wled_read_exp_dimming_map(dev->of_node, wled);
if (rc < 0) {
dev_err(&wled->pdev->dev,
"Reading exponential dimming map failed, rc=%d\n", rc);
return rc;
}
}
wled->sc_irq = platform_get_irq_byname(wled->pdev, "sc-irq");
if (wled->sc_irq < 0)
dev_dbg(&wled->pdev->dev, "sc irq is not used\n");