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

Commit cf1a1b92 authored by Fenglin Wu's avatar Fenglin Wu
Browse files

input: qti-haptics: Add enhancements for effect definitions



Add following enhancements for effect subnode definition:
 1) Allow variable play rate for LRA effects, it can be set different
    with the resonance period of LRA actuator for a weaker vibration.
 2) Update the wf-pattern byte format to include the reverse bit and
    overdrive bit.
 3) Make brake-pattern configurable for each effect.
 4) Make auto resonance configurable for each effect.

Change-Id: Icc74dba10477527a8dc2af1c6ca2119674529b34
Signed-off-by: default avatarFenglin Wu <fenglinw@codeaurora.org>
parent 3840f8ef
Loading
Loading
Loading
Loading
+40 −26
Original line number Diff line number Diff line
@@ -66,19 +66,6 @@ Properties:
		specified in the LRA actuator datasheet. Allowed values are:
		0 to 20475. If this is not specified, 5715us play rate is used.

- qcom,brake-pattern
  Usage:      optional
  Value type: <prop-encoded-array>
  Definition: Specifies the brake pattern with 4 elements used to enable the
		internal reverse braking. Allowed values for each element are:
			0: no brake;
			1: brake with (Vmax / 2) strength;
			2: brake with Vmax strength;
			3: brake with (2 * Vmax) strength;
		If this property is specified with an array of non-zero values,
		then the brake pattern is applied at the end of the playing
		waveform.

- qcom,external-waveform-source
  Usage:      optional
  Value type: <string>
@@ -108,11 +95,12 @@ Following properties are specific only when LRA actuator is used:
		values: "sine", "square". If this is not specified, sinusoid
		resonance driver signal is used.

- qcom,lra-auto-resonance-en
- qcom,lra-allow-variable-play-rate
  Usage:      optional
  Value type: <empty>
  Definition: If specified, the hardware feature of LRA auto resonance detection
		 is enabled for correcting the resonance frequency variation.
  Definition: If specified, "qcom,wf-play-rate-us" for LRA defined in each
		effect could be different with the resonance period of the
		LRA actuator.

- qcom,lra-auto-resonance-mode
  Usage:      optional
@@ -136,16 +124,20 @@ waveforms/effects:
  Usage:      required
  Value type: <prop-encoded-array>
  Definition: Specifies the waveform pattern in a byte array that will be
		played for the effect-id. Allowed values for each element
		are: 0x00 to 0x1F.
		played for the effect-id. The bit fields of each byte are:
		 [7]: drive direction, 0 - forward; 1 - reverse
		 [6]: overdrive, 0 -- 1x drive; 1 -- 2x drive
		 [5:1]: waveform amplitude
		 [0]: reserved.

- qcom,wf-play-rate-us
  Usage:      optional
  Value type: <u32>
  Definition: Specifies the play period in microseconds for each byte pattern.
		For LRA actuator, For LRA, it should be set equal to the resonance
		period specified in the LRA actuator datasheet. Allowed values
		are: 0 to 20475.
		Allowed values are: 0 to 20475. For LRA actuator, if
		"qcom,lra-allow-variable-play-rate" is defined, it could be
		set to other values not equal to the resonance period of the
		LRA actuator.

- qcom,wf-repeat-count
  Usage:      optional
@@ -159,6 +151,25 @@ waveforms/effects:
  Definition: Specifies the repeat times for each sample defined in
		qcom,wf-pattern. Allowed values are: 1, 2, 4, 8.

- qcom,wf-brake-pattern
  Usage:      optional
  Value type: <prop-encoded-array>
  Definition: Specifies the brake pattern with 4 elements used to enable the
		internal reverse braking. Allowed values for each element are:
			0: no brake
			1: brake with (Vmax / 2) strength
			2: brake with Vmax strength
			3: brake with (2 * Vmax) strength
		If this property is specified with an array of non-zero values,
		then the brake pattern is applied at the end of the playing
		waveform.

- qcom,lra-auto-resonance-disable
  Usage:      optional
  Value type: <empty>
  Definition: If specified, the hardware feature of LRA auto resonance detection
		is disabled.

Example:
  qcom,haptics@c000 {
	compatible = "qcom,haptics";
@@ -169,20 +180,23 @@ Example:
	qcom,actuator-type = "lra";
	qcom,vmax-mv = <1800>;
	qcom,ilim-ma = <400>;
	qcom,play-rate-us = <4255>;
	qcom,brake-pattern = [03 02 01 00];
	qcom,play-rate-us = <8000>;
	qcom,lra-resonance-sig-shape = "sine";
	qcom,lra-auto-resonance-mode;
	qcom,lra-auto-resonance-mode = "qwd";
	qcom,lra-allow-variable-play-rate;

	wf_0 {
		/* CLICK effect */
		qcom,effect-id = <0>;
		qcom,wf-pattern = [0a 14 1f 1f 1f 1f 14 0a];
		qcom,wf-play-rate-us = <6250>;
		qcom,wf-pattern = [3e 3e 3e];
		qcom,lra-auto-resonance-disable;
	};

	wf_5 {
		/* HEAVY_CLICK effect */
		qcom,effect-id = <5>;
		qcom,wf-pattern = [08 0a 1a 1f 1f 1a 0a 08];
		qcom,wf-play-rate-us = <6250>;
		qcom,wf-pattern = [7e 7e 7e];
	};
  };
+84 −55
Original line number Diff line number Diff line
@@ -176,6 +176,10 @@ struct qti_hap_effect {
	u16			play_rate_us;
	u8			wf_repeat_n;
	u8			wf_s_repeat_n;
	u8			brake[HAP_BRAKE_PATTERN_MAX];
	int			brake_pattern_length;
	bool			brake_en;
	bool			lra_auto_res_disable;
};

struct qti_hap_play_info {
@@ -194,9 +198,7 @@ struct qti_hap_config {
	u16			vmax_mv;
	u16			ilim_ma;
	u16			play_rate_us;
	u8			brake[HAP_BRAKE_PATTERN_MAX];
	bool			brake_en;
	bool			lra_auto_res_en;
	bool			lra_allow_variable_play_rate;
	bool			use_ext_wf_src;
};

@@ -550,6 +552,21 @@ static int qti_haptics_config_brake(struct qti_hap_chip *chip, u8 *brake)
	return rc;
}

static int qti_haptics_lra_auto_res_enable(struct qti_hap_chip *chip, bool en)
{
	int rc;
	u8 addr, val, mask;

	addr = REG_HAP_AUTO_RES_CTRL;
	mask = HAP_AUTO_RES_EN_BIT;
	val = en ? HAP_AUTO_RES_EN_BIT : 0;
	rc = qti_haptics_masked_write(chip, addr, mask, val);
	if (rc < 0)
		dev_err(chip->dev, "set AUTO_RES_CTRL failed, rc=%d\n", rc);

	return rc;
}

static int qti_haptics_load_constant_waveform(struct qti_hap_chip *chip)
{
	struct qti_hap_play_info *play = &chip->play;
@@ -571,6 +588,13 @@ static int qti_haptics_load_constant_waveform(struct qti_hap_chip *chip)
		if (rc < 0)
			return rc;

		/* Enable Auto-Resonance when VMAX wf-src is selected */
		if (config->act_type == ACT_LRA) {
			rc = qti_haptics_lra_auto_res_enable(chip, true);
			if (rc < 0)
				return rc;
		}

		/* Set WF_SOURCE to VMAX */
		rc = qti_haptics_config_wf_src(chip, INT_WF_VMAX);
		if (rc < 0)
@@ -626,14 +650,22 @@ static int qti_haptics_load_predefined_effect(struct qti_hap_chip *chip,
	if (rc < 0)
		return rc;

	/* override play-rate for ERM here, no need for LRA */
	if (config->act_type == ACT_ERM) {
		rc = qti_haptics_config_play_rate_us(chip,
				play->effect->play_rate_us);
	rc = qti_haptics_config_play_rate_us(chip, play->effect->play_rate_us);
	if (rc < 0)
		return rc;

	if (config->act_type == ACT_LRA) {
		rc = qti_haptics_lra_auto_res_enable(chip,
				!play->effect->lra_auto_res_disable);
		if (rc < 0)
			return rc;
	}

	/* Set brake pattern in the effect */
	rc = qti_haptics_config_brake(chip, play->effect->brake);
	if (rc < 0)
		return rc;

	rc = qti_haptics_config_wf_buffer(chip);
	if (rc < 0)
		return rc;
@@ -736,16 +768,14 @@ static irqreturn_t qti_haptics_sc_irq_handler(int irq, void *data)
static inline void get_play_length(struct qti_hap_play_info *play,
		int *length_us)
{
	struct qti_hap_chip *chip = container_of(play,
			struct qti_hap_chip, play);
	struct qti_hap_effect *effect = play->effect;
	int tmp;

	tmp = effect->pattern_length * effect->play_rate_us;
	tmp *= wf_s_repeat[effect->wf_s_repeat_n];
	tmp *= wf_repeat[effect->wf_repeat_n];
	if (chip->config.brake_en)
		tmp += effect->play_rate_us * HAP_BRAKE_PATTERN_MAX;
	if (effect->brake_en)
		tmp += effect->play_rate_us * effect->brake_pattern_length;

	*length_us = tmp;
}
@@ -954,9 +984,8 @@ static int qti_haptics_hw_init(struct qti_hap_chip *chip)
	/* Set HAP_EN_CTL3 */
	addr = REG_HAP_EN_CTL3;
	val = HAP_HBRIDGE_EN_BIT | HAP_PWM_SIGNAL_EN_BIT | HAP_ILIM_EN_BIT |
		HAP_ILIM_CC_EN_BIT | HAP_DAC_EN_BIT | HAP_PWM_CTL_EN_BIT;
	if (config->act_type == ACT_LRA && config->lra_auto_res_en)
		val |= HAP_AUTO_RES_RBIAS_EN_BIT;
		HAP_ILIM_CC_EN_BIT | HAP_AUTO_RES_RBIAS_EN_BIT |
		HAP_DAC_EN_BIT | HAP_PWM_CTL_EN_BIT;
	rc = qti_haptics_write(chip, addr, &val, 1);
	if (rc < 0) {
		dev_err(chip->dev, "set EN_CTL3 failed, rc=%d\n", rc);
@@ -981,11 +1010,6 @@ static int qti_haptics_hw_init(struct qti_hap_chip *chip)
	if (rc < 0)
		return rc;

	/* Set default brake pattern */
	rc = qti_haptics_config_brake(chip, config->brake);
	if (rc < 0)
		return rc;

	/* Set external waveform source if it's used */
	if (config->use_ext_wf_src) {
		rc = qti_haptics_config_wf_src(chip, config->ext_src);
@@ -1008,10 +1032,6 @@ static int qti_haptics_hw_init(struct qti_hap_chip *chip)
		return rc;
	}

	/* Skip configurations below if auto-res-en is not set */
	if (!config->lra_auto_res_en)
		return 0;

	addr = REG_HAP_AUTO_RES_CFG;
	mask = HAP_AUTO_RES_MODE_BIT | HAP_CAL_EOP_EN_BIT | HAP_CAL_PERIOD_MASK;
	val = config->lra_auto_res_mode << HAP_AUTO_RES_MODE_SHIFT;
@@ -1023,8 +1043,9 @@ static int qti_haptics_hw_init(struct qti_hap_chip *chip)
	}

	addr = REG_HAP_AUTO_RES_CTRL;
	val = HAP_AUTO_RES_EN_BIT | HAP_SEL_AUTO_RES_PERIOD | AUTO_RES_EN_DLY(4)
		| AUTO_RES_CNT_ERR_DELTA(2) | HAP_AUTO_RES_ERR_RECOVERY_BIT;
	val = HAP_AUTO_RES_EN_BIT | HAP_SEL_AUTO_RES_PERIOD |
		AUTO_RES_CNT_ERR_DELTA(2) | HAP_AUTO_RES_ERR_RECOVERY_BIT |
		AUTO_RES_EN_DLY(4);
	rc = qti_haptics_write(chip, addr, &val, 1);
	if (rc < 0) {
		dev_err(chip->dev, "set AUTO_RES_CTRL failed, rc=%d\n",
@@ -1096,30 +1117,6 @@ static int qti_haptics_parse_dt(struct qti_hap_chip *chip)
		config->play_rate_us = (tmp >= HAP_PLAY_RATE_US_MAX) ?
			HAP_PLAY_RATE_US_MAX : tmp;

	tmp = of_property_count_elems_of_size(node, "qcom,brake-pattern",
			sizeof(u8));
	if (tmp > 0) {
		if (tmp != HAP_BRAKE_PATTERN_MAX) {
			dev_err(chip->dev, "brake-pattern should be %d bytes\n",
					HAP_BRAKE_PATTERN_MAX);
			return -EINVAL;
		}

		rc = of_property_read_u8_array(node, "qcom,brake-pattern",
				config->brake, HAP_BRAKE_PATTERN_MAX);
		if (rc < 0) {
			dev_err(chip->dev, "Failed to get brake-pattern, rc=%d\n",
					rc);
			return rc;
		}

		for (val = 0, j = 0; j < HAP_BRAKE_PATTERN_MAX; j++)
			val |= (config->brake[j] & HAP_BRAKE_PATTERN_MASK) <<
				j * HAP_BRAKE_PATTERN_SHIFT;

		config->brake_en = (val != 0);
	}

	if (of_find_property(node, "qcom,external-waveform-source", NULL)) {
		if (!of_property_read_string(node,
				"qcom,external-waveform-source", &str)) {
@@ -1162,8 +1159,8 @@ static int qti_haptics_parse_dt(struct qti_hap_chip *chip)
			}
		}

		config->lra_auto_res_en = of_property_read_bool(node,
				"qcom,lra-auto-resonance-en");
		config->lra_allow_variable_play_rate = of_property_read_bool(
				node, "qcom,lra-allow-variable-play-rate");

		config->lra_auto_res_mode = AUTO_RES_MODE_ZXD;
		rc = of_property_read_string(node,
@@ -1233,10 +1230,6 @@ static int qti_haptics_parse_dt(struct qti_hap_chip *chip)
			return rc;
		}

		for (j = 0; j < effect->pattern_length; j++)
			effect->pattern[j] = effect->pattern[j] <<
				HAP_WF_AMP_SHIFT;

		effect->play_rate_us = config->play_rate_us;
		rc = of_property_read_u32(child_node, "qcom,wf-play-rate-us",
				&tmp);
@@ -1247,6 +1240,7 @@ static int qti_haptics_parse_dt(struct qti_hap_chip *chip)
			effect->play_rate_us = tmp;

		if (config->act_type == ACT_LRA &&
				!config->lra_allow_variable_play_rate &&
				config->play_rate_us != effect->play_rate_us) {
			dev_warn(chip->dev, "play rate should match with LRA resonance frequency\n");
			effect->play_rate_us = config->play_rate_us;
@@ -1277,6 +1271,41 @@ static int qti_haptics_parse_dt(struct qti_hap_chip *chip)

			effect->wf_s_repeat_n = j;
		}

		effect->lra_auto_res_disable = of_property_read_bool(node,
				"qcom,lra-auto-resonance-disable");

		tmp = of_property_count_elems_of_size(child_node,
				"qcom,wf-brake-pattern", sizeof(u8));
		if (tmp <= 0)
			continue;

		if (tmp > HAP_BRAKE_PATTERN_MAX) {
			dev_err(chip->dev, "wf-brake-pattern shouldn't be more than %d bytes\n",
					HAP_BRAKE_PATTERN_MAX);
			return -EINVAL;
		}

		rc = of_property_read_u8_array(child_node,
				"qcom,wf-brake-pattern", effect->brake, tmp);
		if (rc < 0) {
			dev_err(chip->dev, "Failed to get wf-brake-pattern, rc=%d\n",
					rc);
			return rc;
		}

		effect->brake_pattern_length = tmp;
		for (j = tmp - 1; j >= 0; j--) {
			if (effect->brake[j] != 0)
				break;
			effect->brake_pattern_length--;
		}

		for (val = 0, j = 0; j < effect->brake_pattern_length; j++)
			val |= (effect->brake[j] & HAP_BRAKE_PATTERN_MASK)
				<< j * HAP_BRAKE_PATTERN_SHIFT;

		effect->brake_en = (val != 0);
	}

	return 0;