Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d02fbd0d authored by Jishnu Prakash's avatar Jishnu Prakash
Browse files

backlight: qcom-spmi-wled: Add support for exponential dimming



Add support to enable writing a lookup table of brightness values
into WLED_SINK peripheral to enable more granular control over
brightness, to help end user see brightness change smoothly
instead of in visible steps.

Change-Id: Ifd2dd382bf3e1274a5b994e8d83b87833c975970
Signed-off-by: default avatarJishnu Prakash <jprakash@codeaurora.org>
parent ff3868e2
Loading
Loading
Loading
Loading
+109 −0
Original line number Original line Diff line number Diff line
@@ -180,6 +180,21 @@


#define  WLED5_SINK_FLASH_SHDN_CLR_REG	0xb6
#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_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 {
enum wled_version {
	WLED_PMI8998 = 4,
	WLED_PMI8998 = 4,
	WLED_PM660L,
	WLED_PM660L,
@@ -211,6 +226,7 @@ struct wled_config {
	bool en_cabc;
	bool en_cabc;
	bool ext_pfet_sc_pro_en;
	bool ext_pfet_sc_pro_en;
	bool auto_calib_enabled;
	bool auto_calib_enabled;
	bool use_exp_dimming;
};
};


struct wled_flash_config {
struct wled_flash_config {
@@ -258,6 +274,7 @@ struct wled {
	enum wled_flash_mode flash_mode;
	enum wled_flash_mode flash_mode;
	u8 num_strings;
	u8 num_strings;
	u32 leds_per_string;
	u32 leds_per_string;
	u32 exp_map[EXP_DIMMING_TABLE_SIZE];
};
};


enum wled5_mod_sel {
enum wled5_mod_sel {
@@ -1099,6 +1116,78 @@ static inline u8 get_wled_safety_time(int time_ms)
	return 0;
	return 0;
}
}


static int wled_read_exp_dimming_map(struct device_node *node, struct wled *wled)
{
	int rc = 0, len;

	if (*wled->version != WLED_PM7325B) {
		pr_err("Exponential dimming not supported for WLED version %d\n", *wled->version);
		return 0;
	}

	len = of_property_count_elems_of_size(node, "qcom,exp-dimming-map", sizeof(u32));
	if (len != EXP_DIMMING_TABLE_SIZE) {
		pr_err("Invalid exponential map length: %d, must be 256 bytes length\n", len);
		return -EINVAL;
	}

	rc = of_property_read_u32_array(node, "qcom,exp-dimming-map",
					wled->exp_map, EXP_DIMMING_TABLE_SIZE);
	if (rc < 0)
		pr_err("Error in reading qcom,exp-dimming-map, rc=%d\n", rc);

	return rc;
}

static int wled_program_exp_dimming(struct wled *wled)
{
	int rc = 0, i;
	u8 val[4];

	if (*wled->version != WLED_PM7325B) {
		pr_err("Exponential dimming not supported for WLED version %d\n", *wled->version);
		return 0;
	}

	wled_module_enable(wled, 0);

	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) {
		wled_module_enable(wled, 1);
		return rc;
	}

	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:
	regmap_update_bits(wled->regmap,
			wled->sink_addr + WLED5_SINK_BRIGHTNESS_SLEW_RATE_CTL_REG,
			WLED5_EN_EXP_LUT, 0);

	wled_module_enable(wled, 1);
	return rc;
}

static int wled5_setup(struct wled *wled)
static int wled5_setup(struct wled *wled)
{
{
	int rc, temp, i;
	int rc, temp, i;
@@ -1199,6 +1288,14 @@ static int wled5_setup(struct wled *wled)
	if (rc < 0)
	if (rc < 0)
		return rc;
		return rc;


	if (wled->cfg.use_exp_dimming) {
		rc = wled_program_exp_dimming(wled);
		if (rc < 0) {
			pr_err("Programming exponential dimming map failed, rc=%d\n", rc);
			return rc;
		}
	}

	if (wled->ovp_irq >= 0) {
	if (wled->ovp_irq >= 0) {
		rc = devm_request_threaded_irq(&wled->pdev->dev, wled->ovp_irq,
		rc = devm_request_threaded_irq(&wled->pdev->dev, wled->ovp_irq,
				NULL, wled_ovp_irq_handler, IRQF_ONESHOT,
				NULL, wled_ovp_irq_handler, IRQF_ONESHOT,
@@ -1374,6 +1471,7 @@ static const struct wled_config wled4_config_defaults = {
	.en_cabc = 0,
	.en_cabc = 0,
	.ext_pfet_sc_pro_en = 0,
	.ext_pfet_sc_pro_en = 0,
	.auto_calib_enabled = 0,
	.auto_calib_enabled = 0,
	.use_exp_dimming = 0,
};
};


static const struct wled_config wled5_config_defaults = {
static const struct wled_config wled5_config_defaults = {
@@ -1387,6 +1485,7 @@ static const struct wled_config wled5_config_defaults = {
	.en_cabc = 0,
	.en_cabc = 0,
	.ext_pfet_sc_pro_en = 0,
	.ext_pfet_sc_pro_en = 0,
	.auto_calib_enabled = 0,
	.auto_calib_enabled = 0,
	.use_exp_dimming = 0,
};
};


struct wled_var_cfg {
struct wled_var_cfg {
@@ -2252,6 +2351,7 @@ static int wled_configure(struct wled *wled, struct device *dev)
		{ "qcom,en-cabc", &cfg->en_cabc, },
		{ "qcom,en-cabc", &cfg->en_cabc, },
		{ "qcom,ext-pfet-sc-pro", &cfg->ext_pfet_sc_pro_en, },
		{ "qcom,ext-pfet-sc-pro", &cfg->ext_pfet_sc_pro_en, },
		{ "qcom,auto-calibration", &cfg->auto_calib_enabled, },
		{ "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);
	prop_addr = of_get_address(dev->of_node, 0, NULL, NULL);
@@ -2324,6 +2424,15 @@ static int wled_configure(struct wled *wled, struct device *dev)
			*bool_opts[i].val_ptr = true;
			*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");
	wled->sc_irq = platform_get_irq_byname(wled->pdev, "sc-irq");
	if (wled->sc_irq < 0)
	if (wled->sc_irq < 0)
		dev_dbg(&wled->pdev->dev, "sc irq is not used\n");
		dev_dbg(&wled->pdev->dev, "sc irq is not used\n");