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

Commit a8136a02 authored by Devesh Jhunjhunwala's avatar Devesh Jhunjhunwala
Browse files

leds: qpnp-wled: Fix configuration of avdd_trim registers



Currently the avdd_trim registers are being configured incorrectly.
Update the sequence to configure the trim register and the OVP
register based on predetermined values mapped to the target voltage
specified in the device tree. Also add support for performing
masked writes to the wled registers.

CRs-Fixed: 1010716
Change-Id: I4c99b598d5f484368712eab239f7de70b727c2aa
Signed-off-by: default avatarDevesh Jhunjhunwala <deveshj@codeaurora.org>
parent 0c3a23a4
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -54,7 +54,10 @@ Optional properties if 'qcom,disp-type-amoled' is mentioned in DT:
- qcom,loop-ea-gm	: control the gm for gm stage in control loop. default is 3.
- qcom,loop-comp-res-kohm	: control to select the compensation resistor in kohm. default is 320.
- qcom,vref-psm-mv	: reference psm voltage in mv. default for amoled is 450.
- qcom,avdd-trim-steps-from-center : The number of steps to trim the OVP threshold voltage. The possible values can be between -7 to 8.
- qcom,avdd-target-voltage-mv: The target voltage desired for the AVDD module in mV.
				The supported values are:
				7900, 7600, 7300, 6400, 6100, 5800.
				If not specified, default value used is 7600.

Example:
	qcom,leds@d800 {
+96 −28
Original line number Diff line number Diff line
@@ -46,10 +46,12 @@
#define QPNP_WLED_VLOOP_COMP_GM_REG(b)	(b + 0x56)
#define QPNP_WLED_PSM_CTRL_REG(b)	(b + 0x5B)
#define QPNP_WLED_SC_PRO_REG(b)		(b + 0x5E)
#define QPNP_WLED_CTRL_SPARE_REG(b)	(b + 0xDF)
#define QPNP_WLED_TEST1_REG(b)		(b + 0xE2)
#define QPNP_WLED_TEST4_REG(b)		(b + 0xE5)
#define QPNP_WLED_REF_7P7_TRIM_REG(b)	(b + 0xF2)

#define QPNP_WLED_7P7_TRIM_MASK		0xF
#define QPNP_WLED_EN_MASK		0x7F
#define QPNP_WLED_EN_SHIFT		7
#define QPNP_WLED_FDBK_OP_MASK		0xF8
@@ -76,9 +78,6 @@
#define QPNP_WLED_VREF_PSM_MAX_MV			750
#define QPNP_WLED_VREF_PSM_DFLT_AMOLED_MV		450
#define QPNP_WLED_PSM_CTRL_OVERWRITE			0x80
#define QPNP_WLED_AVDD_MIN_TRIM_VALUE			-7
#define QPNP_WLED_AVDD_MAX_TRIM_VALUE			8
#define QPNP_WLED_AVDD_TRIM_CENTER_VALUE		7

#define QPNP_WLED_ILIM_MASK		0xF8
#define QPNP_WLED_ILIM_MIN_MA		105
@@ -195,6 +194,12 @@
#define QPNP_WLED_MIN_MSLEEP		20
#define QPNP_WLED_SC_DLY_MS		20

#define NUM_SUPPORTED_AVDD_VOLTAGES		6
#define QPNP_WLED_AVDD_DEFAULT_VOLTAGE_MV	7600
#define QPNP_WLED_AVDD_MIN_TRIM_VALUE		0x0
#define QPNP_WLED_AVDD_MAX_TRIM_VALUE		0xF
#define QPNP_WLED_AVDD_SET_BIT			BIT(4)

/* output feedback mode */
enum qpnp_wled_fdbk_op {
	QPNP_WLED_FDBK_AUTO,
@@ -227,6 +232,18 @@ static u8 qpnp_wled_sink_dbg_regs[] = {
	0xe6,
};

static int qpnp_wled_avdd_target_voltages[NUM_SUPPORTED_AVDD_VOLTAGES] = {
	7900, 7600, 7300, 6400, 6100, 5800,
};

static u8 qpnp_wled_ovp_reg_settings[NUM_SUPPORTED_AVDD_VOLTAGES] = {
	0x0, 0x0, 0x1, 0x2, 0x2, 0x3,
};

static int qpnp_wled_avdd_trim_adjustments[NUM_SUPPORTED_AVDD_VOLTAGES] = {
	3, 0, -2, 7, 3, 3,
};

/**
 *  qpnp_wled - wed data structure
 *  @ cdev - led class device
@@ -238,7 +255,7 @@ static u8 qpnp_wled_sink_dbg_regs[] = {
 *  @ ovp_irq - over voltage protection irq
 *  @ sc_irq - short circuit irq
 *  @ sc_cnt - short circuit irq count
 *  @ avdd_trim_steps_from_center - number of steps to trim from center value
 *  @ avdd_target_voltage_mv - target voltage for AVDD module in mV
 *  @ ctrl_base - base address for wled ctrl
 *  @ sink_base - base address for wled sink
 *  @ ibb_base - base address for IBB(Inverting Buck Boost)
@@ -279,7 +296,7 @@ struct qpnp_wled {
	int ovp_irq;
	int sc_irq;
	u32 sc_cnt;
	u32 avdd_trim_steps_from_center;
	u32 avdd_target_voltage_mv;
	u16 ctrl_base;
	u16 sink_base;
	u16 mod_freq_khz;
@@ -338,6 +355,24 @@ static int qpnp_wled_write_reg(struct qpnp_wled *wled, u8 *data, u16 addr)
	return rc;
}

static int qpnp_wled_masked_write_reg(struct qpnp_wled *wled, u8 mask, u8 *data,
					u16 addr)
{
	u8 reg;
	int rc;

	rc = qpnp_wled_read_reg(wled, &reg, addr);
	if (rc < 0)
		return rc;

	reg &= ~mask;
	reg |= *data & mask;

	rc = qpnp_wled_write_reg(wled, &reg, addr);

	return rc;
}

static int qpnp_wled_sec_access(struct qpnp_wled *wled, u16 base_addr)
{
	int rc;
@@ -1094,29 +1129,58 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
	if (rc)
		return rc;

	if (wled->disp_type_amoled) {
		/* Configure avdd trim register */
		rc = qpnp_wled_sec_access(wled, wled->ctrl_base);
		if (rc)
	rc = qpnp_wled_read_reg(wled, &reg,
			QPNP_WLED_CTRL_SPARE_REG(wled->ctrl_base));
	if (rc < 0)
		return rc;

		/* Check if wled->avdd_trim_steps_from_center is negative */
		if ((s32)wled->avdd_trim_steps_from_center <
					QPNP_WLED_AVDD_MIN_TRIM_VALUE) {
			wled->avdd_trim_steps_from_center =
					QPNP_WLED_AVDD_MIN_TRIM_VALUE;
		} else if ((s32)wled->avdd_trim_steps_from_center >
						QPNP_WLED_AVDD_MAX_TRIM_VALUE) {
			wled->avdd_trim_steps_from_center =
					QPNP_WLED_AVDD_MAX_TRIM_VALUE;
	/*
	 * Configure TRIM_REG only if disp_type_amoled and it has
	 * not already been programmed by bootloader.
	 */
	if (wled->disp_type_amoled && !(reg & QPNP_WLED_AVDD_SET_BIT)) {
		for (i = 0; i < NUM_SUPPORTED_AVDD_VOLTAGES; i++) {
			if (wled->avdd_target_voltage_mv ==
					qpnp_wled_avdd_target_voltages[i])
				break;
		}
		reg = wled->avdd_trim_steps_from_center +
					QPNP_WLED_AVDD_TRIM_CENTER_VALUE;

		if (i == NUM_SUPPORTED_AVDD_VOLTAGES) {
			dev_err(&wled->spmi->dev,
				"Invalid avdd target voltage specified in device tree\n");
			return -EINVAL;
		}

		/* Update WLED_OVP register based on desired target voltage */
		reg = qpnp_wled_ovp_reg_settings[i];
		rc = qpnp_wled_write_reg(wled, &reg,
			QPNP_WLED_OVP_REG(wled->ctrl_base));
		if (rc)
			return rc;

		/* Update WLED_TRIM register based on desired target voltage */
		rc = qpnp_wled_read_reg(wled, &reg,
			QPNP_WLED_REF_7P7_TRIM_REG(wled->ctrl_base));
		if (rc)
			return rc;
		reg += qpnp_wled_avdd_trim_adjustments[i];
		if ((s8)reg < QPNP_WLED_AVDD_MIN_TRIM_VALUE ||
				(s8)reg > QPNP_WLED_AVDD_MAX_TRIM_VALUE) {
			dev_info(&wled->spmi->dev,
				 "adjusted trim %d is not within range, capping it\n",
				 (s8)reg);
			if ((s8)reg < QPNP_WLED_AVDD_MIN_TRIM_VALUE)
				reg = QPNP_WLED_AVDD_MIN_TRIM_VALUE;
			else
				reg = QPNP_WLED_AVDD_MAX_TRIM_VALUE;
		}
		rc = qpnp_wled_sec_access(wled, wled->ctrl_base);
		if (rc)
			return rc;
		rc = qpnp_wled_masked_write_reg(wled, QPNP_WLED_7P7_TRIM_MASK,
			&reg, QPNP_WLED_REF_7P7_TRIM_REG(wled->ctrl_base));
		if (rc)
			return rc;
	}

	/* Configure the MODULATION register */
@@ -1443,14 +1507,18 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled)
			return rc;
		}

		wled->avdd_trim_steps_from_center = 0;
		rc = of_property_read_u32(spmi->dev.of_node,
				"qcom,avdd-trim-steps-from-center", &temp_val);
				"qcom,avdd-target-voltage-mv", &temp_val);
		if (!rc) {
			wled->avdd_trim_steps_from_center = temp_val;
		} else if (rc != -EINVAL) {
			dev_err(&spmi->dev, "Unable to read avdd trim steps from center value\n");
			wled->avdd_target_voltage_mv = temp_val;
		} else {
			if (rc != -EINVAL)
				return rc;
			dev_info(&spmi->dev,
				 "qcom,avdd-target-voltage-mv not specified. Using default value of %d\n",
				 QPNP_WLED_AVDD_DEFAULT_VOLTAGE_MV);
			wled->avdd_target_voltage_mv =
				QPNP_WLED_AVDD_DEFAULT_VOLTAGE_MV;
		}
	}