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 Original line Diff line number Diff line
@@ -66,19 +66,6 @@ Properties:
		specified in the LRA actuator datasheet. Allowed values are:
		specified in the LRA actuator datasheet. Allowed values are:
		0 to 20475. If this is not specified, 5715us play rate is used.
		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
- qcom,external-waveform-source
  Usage:      optional
  Usage:      optional
  Value type: <string>
  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
		values: "sine", "square". If this is not specified, sinusoid
		resonance driver signal is used.
		resonance driver signal is used.


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


- qcom,lra-auto-resonance-mode
- qcom,lra-auto-resonance-mode
  Usage:      optional
  Usage:      optional
@@ -136,16 +124,20 @@ waveforms/effects:
  Usage:      required
  Usage:      required
  Value type: <prop-encoded-array>
  Value type: <prop-encoded-array>
  Definition: Specifies the waveform pattern in a byte array that will be
  Definition: Specifies the waveform pattern in a byte array that will be
		played for the effect-id. Allowed values for each element
		played for the effect-id. The bit fields of each byte are:
		are: 0x00 to 0x1F.
		 [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
- qcom,wf-play-rate-us
  Usage:      optional
  Usage:      optional
  Value type: <u32>
  Value type: <u32>
  Definition: Specifies the play period in microseconds for each byte pattern.
  Definition: Specifies the play period in microseconds for each byte pattern.
		For LRA actuator, For LRA, it should be set equal to the resonance
		Allowed values are: 0 to 20475. For LRA actuator, if
		period specified in the LRA actuator datasheet. Allowed values
		"qcom,lra-allow-variable-play-rate" is defined, it could be
		are: 0 to 20475.
		set to other values not equal to the resonance period of the
		LRA actuator.


- qcom,wf-repeat-count
- qcom,wf-repeat-count
  Usage:      optional
  Usage:      optional
@@ -159,6 +151,25 @@ waveforms/effects:
  Definition: Specifies the repeat times for each sample defined in
  Definition: Specifies the repeat times for each sample defined in
		qcom,wf-pattern. Allowed values are: 1, 2, 4, 8.
		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:
Example:
  qcom,haptics@c000 {
  qcom,haptics@c000 {
	compatible = "qcom,haptics";
	compatible = "qcom,haptics";
@@ -169,20 +180,23 @@ Example:
	qcom,actuator-type = "lra";
	qcom,actuator-type = "lra";
	qcom,vmax-mv = <1800>;
	qcom,vmax-mv = <1800>;
	qcom,ilim-ma = <400>;
	qcom,ilim-ma = <400>;
	qcom,play-rate-us = <4255>;
	qcom,play-rate-us = <8000>;
	qcom,brake-pattern = [03 02 01 00];
	qcom,lra-resonance-sig-shape = "sine";
	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 {
	wf_0 {
		/* CLICK effect */
		/* CLICK effect */
		qcom,effect-id = <0>;
		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 {
	wf_5 {
		/* HEAVY_CLICK effect */
		/* HEAVY_CLICK effect */
		qcom,effect-id = <5>;
		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 Original line Diff line number Diff line
@@ -176,6 +176,10 @@ struct qti_hap_effect {
	u16			play_rate_us;
	u16			play_rate_us;
	u8			wf_repeat_n;
	u8			wf_repeat_n;
	u8			wf_s_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 {
struct qti_hap_play_info {
@@ -194,9 +198,7 @@ struct qti_hap_config {
	u16			vmax_mv;
	u16			vmax_mv;
	u16			ilim_ma;
	u16			ilim_ma;
	u16			play_rate_us;
	u16			play_rate_us;
	u8			brake[HAP_BRAKE_PATTERN_MAX];
	bool			lra_allow_variable_play_rate;
	bool			brake_en;
	bool			lra_auto_res_en;
	bool			use_ext_wf_src;
	bool			use_ext_wf_src;
};
};


@@ -550,6 +552,21 @@ static int qti_haptics_config_brake(struct qti_hap_chip *chip, u8 *brake)
	return rc;
	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)
static int qti_haptics_load_constant_waveform(struct qti_hap_chip *chip)
{
{
	struct qti_hap_play_info *play = &chip->play;
	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)
		if (rc < 0)
			return rc;
			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 */
		/* Set WF_SOURCE to VMAX */
		rc = qti_haptics_config_wf_src(chip, INT_WF_VMAX);
		rc = qti_haptics_config_wf_src(chip, INT_WF_VMAX);
		if (rc < 0)
		if (rc < 0)
@@ -626,14 +650,22 @@ static int qti_haptics_load_predefined_effect(struct qti_hap_chip *chip,
	if (rc < 0)
	if (rc < 0)
		return rc;
		return rc;


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

	if (config->act_type == ACT_LRA) {
		rc = qti_haptics_lra_auto_res_enable(chip,
				!play->effect->lra_auto_res_disable);
		if (rc < 0)
		if (rc < 0)
			return rc;
			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);
	rc = qti_haptics_config_wf_buffer(chip);
	if (rc < 0)
	if (rc < 0)
		return rc;
		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,
static inline void get_play_length(struct qti_hap_play_info *play,
		int *length_us)
		int *length_us)
{
{
	struct qti_hap_chip *chip = container_of(play,
			struct qti_hap_chip, play);
	struct qti_hap_effect *effect = play->effect;
	struct qti_hap_effect *effect = play->effect;
	int tmp;
	int tmp;


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


	*length_us = tmp;
	*length_us = tmp;
}
}
@@ -954,9 +984,8 @@ static int qti_haptics_hw_init(struct qti_hap_chip *chip)
	/* Set HAP_EN_CTL3 */
	/* Set HAP_EN_CTL3 */
	addr = REG_HAP_EN_CTL3;
	addr = REG_HAP_EN_CTL3;
	val = HAP_HBRIDGE_EN_BIT | HAP_PWM_SIGNAL_EN_BIT | HAP_ILIM_EN_BIT |
	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;
		HAP_ILIM_CC_EN_BIT | HAP_AUTO_RES_RBIAS_EN_BIT |
	if (config->act_type == ACT_LRA && config->lra_auto_res_en)
		HAP_DAC_EN_BIT | HAP_PWM_CTL_EN_BIT;
		val |= HAP_AUTO_RES_RBIAS_EN_BIT;
	rc = qti_haptics_write(chip, addr, &val, 1);
	rc = qti_haptics_write(chip, addr, &val, 1);
	if (rc < 0) {
	if (rc < 0) {
		dev_err(chip->dev, "set EN_CTL3 failed, rc=%d\n", rc);
		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)
	if (rc < 0)
		return rc;
		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 */
	/* Set external waveform source if it's used */
	if (config->use_ext_wf_src) {
	if (config->use_ext_wf_src) {
		rc = qti_haptics_config_wf_src(chip, config->ext_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;
		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;
	addr = REG_HAP_AUTO_RES_CFG;
	mask = HAP_AUTO_RES_MODE_BIT | HAP_CAL_EOP_EN_BIT | HAP_CAL_PERIOD_MASK;
	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;
	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;
	addr = REG_HAP_AUTO_RES_CTRL;
	val = HAP_AUTO_RES_EN_BIT | HAP_SEL_AUTO_RES_PERIOD | AUTO_RES_EN_DLY(4)
	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_CNT_ERR_DELTA(2) | HAP_AUTO_RES_ERR_RECOVERY_BIT |
		AUTO_RES_EN_DLY(4);
	rc = qti_haptics_write(chip, addr, &val, 1);
	rc = qti_haptics_write(chip, addr, &val, 1);
	if (rc < 0) {
	if (rc < 0) {
		dev_err(chip->dev, "set AUTO_RES_CTRL failed, rc=%d\n",
		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) ?
		config->play_rate_us = (tmp >= HAP_PLAY_RATE_US_MAX) ?
			HAP_PLAY_RATE_US_MAX : tmp;
			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_find_property(node, "qcom,external-waveform-source", NULL)) {
		if (!of_property_read_string(node,
		if (!of_property_read_string(node,
				"qcom,external-waveform-source", &str)) {
				"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,
		config->lra_allow_variable_play_rate = of_property_read_bool(
				"qcom,lra-auto-resonance-en");
				node, "qcom,lra-allow-variable-play-rate");


		config->lra_auto_res_mode = AUTO_RES_MODE_ZXD;
		config->lra_auto_res_mode = AUTO_RES_MODE_ZXD;
		rc = of_property_read_string(node,
		rc = of_property_read_string(node,
@@ -1233,10 +1230,6 @@ static int qti_haptics_parse_dt(struct qti_hap_chip *chip)
			return rc;
			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;
		effect->play_rate_us = config->play_rate_us;
		rc = of_property_read_u32(child_node, "qcom,wf-play-rate-us",
		rc = of_property_read_u32(child_node, "qcom,wf-play-rate-us",
				&tmp);
				&tmp);
@@ -1247,6 +1240,7 @@ static int qti_haptics_parse_dt(struct qti_hap_chip *chip)
			effect->play_rate_us = tmp;
			effect->play_rate_us = tmp;


		if (config->act_type == ACT_LRA &&
		if (config->act_type == ACT_LRA &&
				!config->lra_allow_variable_play_rate &&
				config->play_rate_us != effect->play_rate_us) {
				config->play_rate_us != effect->play_rate_us) {
			dev_warn(chip->dev, "play rate should match with LRA resonance frequency\n");
			dev_warn(chip->dev, "play rate should match with LRA resonance frequency\n");
			effect->play_rate_us = config->play_rate_us;
			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->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;
	return 0;