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

Commit 4e3ac83b authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "input: qti-haptics: Add a timer to stop playing when the time expired"

parents 2f488b59 30f10b23
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];
	};
  };
+116 −55
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@

#include <linux/device.h>
#include <linux/err.h>
#include <linux/hrtimer.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
@@ -176,6 +177,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 +199,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;
};

@@ -211,6 +214,7 @@ struct qti_hap_chip {
	struct qti_hap_effect		*predefined;
	struct qti_hap_effect		constant;
	struct regulator		*vdd_supply;
	struct hrtimer			stop_timer;
	spinlock_t			bus_lock;
	ktime_t				last_sc_time;
	int				play_irq;
@@ -550,6 +554,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 +590,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 +652,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 +770,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;
}
@@ -871,6 +903,8 @@ static int qti_haptics_playback(struct input_dev *dev, int effect_id, int val)
{
	struct qti_hap_chip *chip = input_get_drvdata(dev);
	struct qti_hap_play_info *play = &chip->play;
	s64 secs;
	unsigned long nsecs;
	int rc = 0;

	dev_dbg(chip->dev, "playback, val = %d\n", val);
@@ -889,6 +923,11 @@ static int qti_haptics_playback(struct input_dev *dev, int effect_id, int val)
				disable_irq_nosync(chip->play_irq);
				chip->play_irq_en = false;
			}
			secs = play->length_us / USEC_PER_SEC;
			nsecs = (play->length_us % USEC_PER_SEC) *
				NSEC_PER_USEC;
			hrtimer_start(&chip->stop_timer, ktime_set(secs, nsecs),
					HRTIMER_MODE_REL);
		}
	} else {
		play->length_us = 0;
@@ -954,9 +993,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 +1019,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 +1041,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 +1052,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",
@@ -1035,6 +1065,26 @@ static int qti_haptics_hw_init(struct qti_hap_chip *chip)
	return 0;
}

static enum hrtimer_restart qti_hap_stop_timer(struct hrtimer *timer)
{
	struct qti_hap_chip *chip = container_of(timer, struct qti_hap_chip,
			stop_timer);
	int rc;

	chip->play.length_us = 0;
	rc = qti_haptics_play(chip, false);
	if (rc < 0) {
		dev_err(chip->dev, "Stop playing failed, rc=%d\n", rc);
		goto err_out;
	}

	rc = qti_haptics_module_en(chip, false);
	if (rc < 0)
		dev_err(chip->dev, "Disable module failed, rc=%d\n", rc);
err_out:
	return HRTIMER_NORESTART;
}

static int qti_haptics_parse_dt(struct qti_hap_chip *chip)
{
	struct qti_hap_config *config = &chip->config;
@@ -1096,30 +1146,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 +1188,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 +1259,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 +1269,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 +1300,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;
@@ -1338,6 +1396,9 @@ static int qti_haptics_probe(struct platform_device *pdev)
		return rc;
	}

	hrtimer_init(&chip->stop_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	chip->stop_timer.function = qti_hap_stop_timer;

	input_dev->name = "vibrator";
	input_set_drvdata(input_dev, chip);
	chip->input_dev = input_dev;