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

Commit 3f684b21 authored by Subbaraman Narayanamurthy's avatar Subbaraman Narayanamurthy
Browse files

leds: qpnp-flash-v2: Add support for LPG strobe



Flash LED3 can be configured for LPG strobe in addition to the
existing HW or SW strobe types. LPG strobe works the same way
as HW strobe except the strobing is controlled by LPG output
instead of a GPIO. To accommodate this, device tree property
"qcom,hw-strobe-sel" got renamed to "qcom,strobe-sel".

While at it, configure hardware strobe option only when the
option is specified through device tree.

Change-Id: I9351d7b7cd8c57ff7707a4ada6c5bdfa42772390
Signed-off-by: default avatarSubbaraman Narayanamurthy <subbaram@codeaurora.org>
parent a7153c30
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -169,8 +169,15 @@ Optional properties:
                          sleep configuration defined for each pin or pin group.
- qcom,hw-strobe-gpio	: phandle to specify GPIO for hardware strobing. This is used when there is no
			  pinctrl support or PMIC GPIOs are used.
- qcom,hw-strobe-sel	: Boolean property to enable hardware strobe. If not defined, software strobe
			  will be used.
- qcom,strobe-sel	: Property to select strobe type. If not defined,
			  software strobe will be used. Allowed options are:
			  0 - SW strobe
			  1 - HW strobe
			  2 - LPG strobe
			  LPG strobe is supported only for LED3.
			  If LPG strobe is specified, then strobe control is
			  configured for active high and level triggered. Also
			  qcom,hw-strobe-option should be set to 1 or 2.
- qcom,hw-strobe-edge-trigger	: Boolean property to select trigger type. If defined, hw-strobe is set to
				  be edge triggered. Otherwise, it is level triggered.
- qcom,hw-strobe-active-low	: Boolean property to select strobe signal polarity. If defined, hw-strobe
+88 −22
Original line number Diff line number Diff line
@@ -63,11 +63,13 @@
#define	FLASH_LED_REG_MITIGATION_SEL(base)	(base + 0x6E)
#define	FLASH_LED_REG_MITIGATION_SW(base)	(base + 0x6F)
#define	FLASH_LED_REG_LMH_LEVEL(base)		(base + 0x70)
#define	FLASH_LED_REG_MULTI_STROBE_CTRL(base)	(base + 0x71)
#define	FLASH_LED_REG_LPG_INPUT_CTRL(base)	(base + 0x72)
#define	FLASH_LED_REG_CURRENT_DERATE_EN(base)	(base + 0x76)

#define	FLASH_LED_HDRM_VOL_MASK			GENMASK(7, 4)
#define	FLASH_LED_CURRENT_MASK			GENMASK(6, 0)
#define	FLASH_LED_ENABLE_MASK			GENMASK(2, 0)
#define	FLASH_LED_STROBE_MASK			GENMASK(1, 0)
#define	FLASH_HW_STROBE_MASK			GENMASK(2, 0)
#define	FLASH_LED_ISC_WARMUP_DELAY_MASK		GENMASK(1, 0)
#define	FLASH_LED_CURRENT_DERATE_EN_MASK	GENMASK(2, 0)
@@ -91,6 +93,9 @@
#define	THERMAL_DERATE_SLOW_SHIFT		4
#define	THERMAL_DERATE_SLOW_MASK		GENMASK(6, 4)
#define	THERMAL_DERATE_FAST_MASK		GENMASK(2, 0)
#define	LED1N2_FLASH_ONCE_ONLY_BIT		BIT(0)
#define	LED3_FLASH_ONCE_ONLY_BIT		BIT(1)
#define	LPG_INPUT_SEL_BIT			BIT(0)

#define	VPH_DROOP_DEBOUNCE_US_TO_VAL(val_us)	(val_us / 8)
#define	VPH_DROOP_HYST_MV_TO_VAL(val_mv)	(val_mv / 25)
@@ -174,6 +179,12 @@ enum {
	LED3,
};

enum strobe_type {
	SW_STROBE = 0,
	HW_STROBE,
	LPG_STROBE,
};

/*
 * Configurations for each individual LED
 */
@@ -194,7 +205,8 @@ struct flash_node_data {
	u8				ires;
	u8				hdrm_val;
	u8				current_reg_val;
	u8				trigger;
	u8				strobe_ctrl;
	u8				strobe_sel;
	bool				led_on;
};

@@ -232,6 +244,7 @@ struct flash_led_platform_data {
	int			thermal_thrsh1;
	int			thermal_thrsh2;
	int			thermal_thrsh3;
	int			hw_strobe_option;
	u32			led1n2_iclamp_low_ma;
	u32			led1n2_iclamp_mid_ma;
	u32			led3_iclamp_low_ma;
@@ -246,7 +259,6 @@ struct flash_led_platform_data {
	u8			chgr_mitigation_sel;
	u8			lmh_level;
	u8			iled_thrsh_val;
	u8			hw_strobe_option;
	bool			hdrm_auto_mode_en;
	bool			thermal_derate_en;
	bool			otst_ramp_bkup_en;
@@ -557,6 +569,28 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
			return rc;
	}

	if (led->pdata->hw_strobe_option > 0) {
		rc = qpnp_flash_led_masked_write(led,
				FLASH_LED_REG_STROBE_CFG(led->base),
				FLASH_LED_STROBE_MASK,
				led->pdata->hw_strobe_option);
		if (rc < 0)
			return rc;
	}

	if (led->fnode[LED3].strobe_sel == LPG_STROBE) {
		rc = qpnp_flash_led_masked_write(led,
			FLASH_LED_REG_MULTI_STROBE_CTRL(led->base),
			LED3_FLASH_ONCE_ONLY_BIT, 0);
		if (rc < 0)
			return rc;

		rc = qpnp_flash_led_masked_write(led,
			FLASH_LED_REG_LPG_INPUT_CTRL(led->base),
			LPG_INPUT_SEL_BIT, LPG_INPUT_SEL_BIT);
		if (rc < 0)
			return rc;
	}
	return 0;
}

@@ -981,7 +1015,7 @@ static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode)

		led->fnode[i].led_on = false;

		if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) {
		if (led->fnode[i].strobe_sel == HW_STROBE) {
			rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i],
					led->pdata->hw_strobe_option, false);
			if (rc < 0) {
@@ -1035,13 +1069,6 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
	if (rc < 0)
		return rc;

	rc = qpnp_flash_led_masked_write(led,
					FLASH_LED_REG_STROBE_CFG(led->base),
					FLASH_LED_ENABLE_MASK,
					led->pdata->hw_strobe_option);
	if (rc < 0)
		return rc;

	val = 0;
	for (i = 0; i < led->num_fnodes; i++) {
		if (!led->fnode[i].led_on ||
@@ -1049,13 +1076,13 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
			continue;

		addr_offset = led->fnode[i].id;
		if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT)
			mask = FLASH_HW_STROBE_MASK;
		else
		if (led->fnode[i].strobe_sel == SW_STROBE)
			mask = FLASH_LED_HW_SW_STROBE_SEL_BIT;
		else
			mask = FLASH_HW_STROBE_MASK;
		rc = qpnp_flash_led_masked_write(led,
			FLASH_LED_REG_STROBE_CTRL(led->base + addr_offset),
			mask, led->fnode[i].trigger);
			mask, led->fnode[i].strobe_ctrl);
		if (rc < 0)
			return rc;

@@ -1073,7 +1100,7 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)

		val |= FLASH_LED_ENABLE << led->fnode[i].id;

		if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) {
		if (led->fnode[i].strobe_sel == HW_STROBE) {
			rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i],
					led->pdata->hw_strobe_option, true);
			if (rc < 0) {
@@ -1365,7 +1392,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
	const char *temp_string;
	int rc, min_ma;
	u32 val;
	bool strobe_sel = 0, edge_trigger = 0, active_high = 0;
	bool hw_strobe = 0, edge_trigger = 0, active_high = 0;

	fnode->pdev = led->pdev;
	fnode->cdev.brightness_set = qpnp_flash_led_brightness_set;
@@ -1484,14 +1511,52 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
		return rc;
	}

	strobe_sel = of_property_read_bool(node, "qcom,hw-strobe-sel");
	if (strobe_sel) {
	fnode->strobe_sel = SW_STROBE;
	rc = of_property_read_u32(node, "qcom,strobe-sel", &val);
	if (rc < 0) {
		if (rc != -EINVAL) {
			pr_err("Unable to read qcom,strobe-sel property\n");
			return rc;
		}
	} else {
		if (val < SW_STROBE || val > LPG_STROBE) {
			pr_err("Incorrect strobe selection specified %d\n",
				val);
			return -EINVAL;
		}
		fnode->strobe_sel = (u8)val;
	}

	/*
	 * LPG strobe is allowed only for LED3 and HW strobe option should be
	 * option 2 or 3.
	 */
	if (fnode->strobe_sel == LPG_STROBE) {
		if (led->pdata->hw_strobe_option ==
				FLASH_LED_HW_STROBE_OPTION_1) {
			pr_err("Incorrect strobe option for LPG strobe\n");
			return -EINVAL;
		}
		if (fnode->id != LED3) {
			pr_err("Incorrect LED chosen for LPG strobe\n");
			return -EINVAL;
		}
	}

	if (fnode->strobe_sel == HW_STROBE) {
		edge_trigger = of_property_read_bool(node,
						"qcom,hw-strobe-edge-trigger");
		active_high = !of_property_read_bool(node,
						"qcom,hw-strobe-active-low");
		hw_strobe = 1;
	} else if (fnode->strobe_sel == LPG_STROBE) {
		/* LPG strobe requires level trigger and active high */
		edge_trigger = 0;
		active_high =  1;
		hw_strobe = 1;
	}
	fnode->trigger = (strobe_sel << 2) | (edge_trigger << 1) | active_high;
	fnode->strobe_ctrl = (hw_strobe << 2) | (edge_trigger << 1) |
				active_high;

	rc = led_classdev_register(&led->pdev->dev, &fnode->cdev);
	if (rc < 0) {
@@ -1507,7 +1572,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
		fnode->strobe_pinctrl = NULL;
	}

	if (fnode->trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) {
	if (fnode->strobe_sel == HW_STROBE) {
		if (of_find_property(node, "qcom,hw-strobe-gpio", NULL)) {
			fnode->hw_strobe_gpio = of_get_named_gpio(node,
						"qcom,hw-strobe-gpio", 0);
@@ -1887,9 +1952,10 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led,

	led->pdata->vph_droop_hysteresis <<= FLASH_LED_VPH_DROOP_HYST_SHIFT;

	led->pdata->hw_strobe_option = -EINVAL;
	rc = of_property_read_u32(node, "qcom,hw-strobe-option", &val);
	if (!rc) {
		led->pdata->hw_strobe_option = (u8)val;
		led->pdata->hw_strobe_option = val;
	} else if (rc != -EINVAL) {
		pr_err("Unable to parse hw strobe option, rc=%d\n", rc);
		return rc;