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

Commit c0a5358a authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

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

parents 9626c8ce d02fbd0d
Loading
Loading
Loading
Loading
+111 −2
Original line number Diff line number Diff line
@@ -180,6 +180,21 @@

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

struct wled_flash_config {
@@ -258,6 +274,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 {
@@ -320,7 +337,7 @@ static int wled_module_enable(struct wled *wled, int val)
		return 0;

	/* Force HFRC off */
	if (is_wled5(wled)) {
	if (*wled->version == WLED_PM8150L) {
		reg = val ? 0 : 3;
		rc = regmap_write(wled->regmap, wled->ctrl_addr +
				  WLED5_CTRL_PBUS_WRITE_SYNC_CTL, reg);
@@ -335,7 +352,7 @@ static int wled_module_enable(struct wled *wled, int val)
		return rc;

	/* Force HFRC off */
	if (is_wled5(wled) && val) {
	if ((*wled->version == WLED_PM8150L) && val) {
		rc = regmap_write(wled->regmap, wled->sink_addr +
				  WLED5_SINK_FLASH_SHDN_CLR_REG, 0);
		if (rc < 0)
@@ -1116,6 +1133,78 @@ 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 = 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)
{
	int rc, temp, i;
@@ -1216,6 +1305,14 @@ static int wled5_setup(struct wled *wled)
	if (rc < 0)
		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) {
		rc = devm_request_threaded_irq(&wled->pdev->dev, wled->ovp_irq,
				NULL, wled_ovp_irq_handler, IRQF_ONESHOT,
@@ -1391,6 +1488,7 @@ static const struct wled_config wled4_config_defaults = {
	.en_cabc = 0,
	.ext_pfet_sc_pro_en = 0,
	.auto_calib_enabled = 0,
	.use_exp_dimming = 0,
};

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

struct wled_var_cfg {
@@ -2269,6 +2368,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);
@@ -2341,6 +2441,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");