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

Commit 12c83e63 authored by Fenglin Wu's avatar Fenglin Wu
Browse files

input: qcom-hv-haptics: add support to operate from non-HBoost regulator



By default, haptics module is supplied from HBoost module and it
talks to HBoost module in hardware to get an appropriate operating
voltage. Haptics module can also be supplied from non-HBoost regulator
and it requires software to request the voltage.

Add support to operate haptics under a fixed voltage from a non-HBoost
regulator. Make the following modifications:
  1) Set voltage and enable the regulator before enabling the play.
  2) Force VREG_RDY signal in haptics module before enabling the play.
  3) Scale the DIRECT_PLAY amplitude to achieve appropriate output
     voltage in constant playing.
  4) Scale the DIRECT_PLAY amplitude instead of Vmax setting for
     gain setting in constant playing.
  5) Adjust the LRA impedance detectability according to the regulator
     output voltage.

Change-Id: If832b6512d7641ad3d271bb68f4bdb7dbb90a5c5
Signed-off-by: default avatarFenglin Wu <fenglinw@codeaurora.org>
parent 20a19395
Loading
Loading
Loading
Loading
+254 −29
Original line number Diff line number Diff line
@@ -142,6 +142,9 @@
#define VMAX_HDRM_STEP_MV			50
#define VMAX_HDRM_MAX_MV			6350

#define HAP_CFG_VSET_CFG_REG			0x68
#define FORCE_VREG_RDY_BIT			BIT(0)

#define HAP_CFG_MOD_STATUS_SEL_REG		0x70
#define MOD_STATUS_SEL_CAL_TLRA_CL_STS_VAL	0
#define MOD_STATUS_SEL_LAST_GOOD_TLRA_VAL	3
@@ -249,6 +252,7 @@
#define CHAR_BRAKE_MODE				24
#define HW_BRAKE_CYCLES				5
#define F_LRA_VARIATION_HZ			5
#define NON_HBOOST_MAX_VMAX_MV			4000

#define MAX_FIFO_SAMPLES(chip)		\
	((chip)->ptn_revision == HAP_PTN_V1 ? 104 : 640)
@@ -427,6 +431,7 @@ struct haptics_hw_config {
	u32			cl_t_lra_us;
	u32			lra_min_mohms;
	u32			lra_max_mohms;
	u32			lra_open_mohms;
	u32			preload_effect;
	u32			fifo_empty_thresh;
	u16			rc_clk_cal_count;
@@ -456,7 +461,9 @@ struct haptics_chip {
	struct nvmem_device		*hap_cfg_nvmem;
	struct device_node		*pbs_node;
	struct class			hap_class;
	struct regulator		*hpwr_vreg;
	int				fifo_empty_irq;
	u32				hpwr_voltage_mv;
	u32				effects_count;
	u32				cfg_addr_base;
	u32				ptn_addr_base;
@@ -467,6 +474,7 @@ struct haptics_chip {
	bool				fifo_empty_irq_en;
	bool				swr_slave_enabled;
	bool				clamp_at_5v;
	bool				hpwr_vreg_enabled;
};

struct haptics_reg_info {
@@ -1055,6 +1063,23 @@ static int haptics_set_vmax_headroom_mv(struct haptics_chip *chip, u32 hdrm_mv)
	return rc;
}

static int haptics_get_vmax_headroom_mv(struct haptics_chip *chip, u32 *hdrm_mv)
{
	int rc;
	u8 val;

	rc = haptics_read(chip, chip->cfg_addr_base,
			HAP_CFG_VMAX_HDRM_REG, &val, 1);
	if (rc < 0) {
		dev_err(chip->dev, "Get Vmax HDRM failed, rc=%d\n",
				rc);
		return rc;
	}

	*hdrm_mv = (val & VMAX_HDRM_MASK) * VMAX_HDRM_STEP_MV;
	return 0;
}

static int haptics_enable_autores(struct haptics_chip *chip, bool en)
{
	int rc;
@@ -1134,32 +1159,73 @@ static bool is_boost_vreg_enabled_in_open_loop(struct haptics_chip *chip)
	return false;
}

static int haptics_enable_play(struct haptics_chip *chip, bool en)
static int haptics_enable_hpwr_vreg(struct haptics_chip *chip, bool en)
{
	struct haptics_play_info *play = &chip->play;
	int rc;
	u8 val;

	if (chip->hpwr_vreg == NULL || chip->hpwr_vreg_enabled == en)
		return 0;

	if (en) {
		val = SC_CLR_BIT | AUTO_RES_ERR_CLR_BIT |
			HPWR_RDY_FAULT_CLR_BIT;
		rc = haptics_write(chip, chip->cfg_addr_base,
				HAP_CFG_FAULT_CLR_REG, &val, 1);
		rc = regulator_set_voltage(chip->hpwr_vreg,
				chip->hpwr_voltage_mv * 1000, INT_MAX);
		if (rc < 0) {
			dev_err(chip->dev, "Set hpwr voltage failed, rc=%d\n",
					rc);
			return rc;
		}

		rc = regulator_enable(chip->hpwr_vreg);
		if (rc < 0) {
			dev_err(chip->dev, "Enable hpwr failed, rc=%d\n",
					rc);
			regulator_set_voltage(chip->hpwr_vreg, 0, INT_MAX);
			return rc;
		}
	} else {
		rc = regulator_disable(chip->hpwr_vreg);
		if (rc < 0) {
			dev_err(chip->dev, "Disable hpwr failed, rc=%d\n",
					rc);
			return rc;
		}

		rc = regulator_set_voltage(chip->hpwr_vreg, 0, INT_MAX);
		if (rc < 0) {
			dev_err(chip->dev, "Set hpwr voltage failed, rc=%d\n",
					rc);
			return rc;
		}
	}

	dev_dbg(chip->dev, "%s hpwr vreg\n", en ? "enabled" : "disabled");
	chip->hpwr_vreg_enabled = en;
	return 0;
}

static int haptics_open_loop_drive_config(struct haptics_chip *chip, bool en)
{
	int rc;
	u8 val;

	if ((is_boost_vreg_enabled_in_open_loop(chip) ||
			chip->hpwr_vreg != NULL) && en) {
		/* Force VREG_RDY */
		val = FORCE_VREG_RDY_BIT;
		rc = haptics_masked_write(chip, chip->cfg_addr_base,
				HAP_CFG_VSET_CFG_REG, FORCE_VREG_RDY_BIT,
				FORCE_VREG_RDY_BIT);
		if (rc < 0)
			return rc;

		/*
		 * Toggle RC_CLK_CAL_EN if it's in auto mode and
		 * haptics boost is working in open loop
		 */
		/* Toggle RC_CLK_CAL_EN if it's in auto mode */
		rc = haptics_read(chip, chip->cfg_addr_base,
				HAP_CFG_CAL_EN_REG, &val, 1);
		if (rc < 0)
			return rc;

		if (((val & CAL_RC_CLK_MASK) ==
				CAL_RC_CLK_AUTO_VAL << CAL_RC_CLK_SHIFT)
				&& is_boost_vreg_enabled_in_open_loop(chip)) {
		if ((val & CAL_RC_CLK_MASK) ==
				CAL_RC_CLK_AUTO_VAL << CAL_RC_CLK_SHIFT) {
			val = CAL_RC_CLK_DISABLED_VAL << CAL_RC_CLK_SHIFT;
			rc = haptics_masked_write(chip, chip->cfg_addr_base,
					HAP_CFG_CAL_EN_REG, CAL_RC_CLK_MASK,
@@ -1176,8 +1242,35 @@ static int haptics_enable_play(struct haptics_chip *chip, bool en)

			dev_dbg(chip->dev, "Toggle CAL_EN in open-loop-VREG playing\n");
		}
	} else {
		val = en ? FORCE_VREG_RDY_BIT : 0;
		rc = haptics_masked_write(chip, chip->cfg_addr_base,
				HAP_CFG_VSET_CFG_REG,
				FORCE_VREG_RDY_BIT, val);
	}

	return rc;
}

static int haptics_enable_play(struct haptics_chip *chip, bool en)
{
	struct haptics_play_info *play = &chip->play;
	int rc;
	u8 val;

	if (en) {
		val = SC_CLR_BIT | AUTO_RES_ERR_CLR_BIT |
			HPWR_RDY_FAULT_CLR_BIT;
		rc = haptics_write(chip, chip->cfg_addr_base,
				HAP_CFG_FAULT_CLR_REG, &val, 1);
		if (rc < 0)
			return rc;
	}

	rc = haptics_open_loop_drive_config(chip, en);
	if (rc < 0)
		return rc;

	val = play->pattern_src;
	if (play->brake && !play->brake->disabled)
		val |= BRAKE_EN_BIT;
@@ -1576,6 +1669,7 @@ static int haptics_set_fifo(struct haptics_chip *chip, struct fifo_cfg *fifo)
static int haptics_load_constant_effect(struct haptics_chip *chip, u8 amplitude)
{
	struct haptics_play_info *play = &chip->play;
	u32 hdrm_mv, vmax_mv = chip->config.vmax_mv;
	int rc = 0;

	mutex_lock(&chip->play.lock);
@@ -1588,8 +1682,17 @@ static int haptics_load_constant_effect(struct haptics_chip *chip, u8 amplitude)
	/* No effect data when playing constant waveform */
	play->effect = NULL;

	/* Fix Vmax to (hpwr_vreg_mv - hdrm_mv) in non-HBOOST regulator case */
	if (chip->hpwr_vreg) {
		rc = haptics_get_vmax_headroom_mv(chip, &hdrm_mv);
		if (rc < 0)
			goto unlock;

		vmax_mv = chip->hpwr_voltage_mv - hdrm_mv;
	}

	/* configure VMAX in case it was changed in previous effect playing */
	rc = haptics_set_vmax_mv(chip, chip->config.vmax_mv);
	rc = haptics_set_vmax_mv(chip, vmax_mv);
	if (rc < 0)
		goto unlock;

@@ -1899,6 +2002,26 @@ static int haptics_load_periodic_effect(struct haptics_chip *chip,
	return rc;
}

static u8 get_direct_play_max_amplitude(struct haptics_chip *chip)
{
	u32 amplitude = DIRECT_PLAY_MAX_AMPLITUDE, hdrm_mv;
	int rc;

	if (chip->hpwr_vreg) {
		rc = haptics_get_vmax_headroom_mv(chip, &hdrm_mv);
		if (rc < 0)
			return 0;

		amplitude *= chip->config.vmax_mv;
		amplitude /= (chip->hpwr_voltage_mv - hdrm_mv);
		if (amplitude > DIRECT_PLAY_MAX_AMPLITUDE)
			amplitude = DIRECT_PLAY_MAX_AMPLITUDE;
	}

	dev_dbg(chip->dev, "max amplitude for direct play: %#x\n", amplitude);
	return (u8)amplitude;
}

static int haptics_upload_effect(struct input_dev *dev,
		struct ff_effect *effect, struct ff_effect *old)
{
@@ -1912,9 +2035,10 @@ static int haptics_upload_effect(struct input_dev *dev,
	case FF_CONSTANT:
		length_us = effect->replay.length * USEC_PER_MSEC;
		level = effect->u.constant.level;
		tmp = level * DIRECT_PLAY_MAX_AMPLITUDE;
		tmp = get_direct_play_max_amplitude(chip);
		tmp *= level;
		amplitude = tmp / 0x7fff;
		dev_dbg(chip->dev, "upload constant effect, length = %dus, amplitude = %d\n",
		dev_dbg(chip->dev, "upload constant effect, length = %dus, amplitude = %#x\n",
				length_us, amplitude);
		haptics_load_constant_effect(chip, amplitude);
		if (rc < 0) {
@@ -1961,7 +2085,11 @@ static int haptics_upload_effect(struct input_dev *dev,
		return -EINVAL;
	}

	return 0;
	rc = haptics_enable_hpwr_vreg(chip, true);
	if (rc < 0)
		dev_err(chip->dev, "enable hpwr_vreg failed, rc=%d\n");

	return rc;
}

static void haptics_fifo_empty_irq_config(struct haptics_chip *chip,
@@ -2065,7 +2193,11 @@ static int haptics_erase(struct input_dev *dev, int effect_id)
		}
	}

	return 0;
	rc = haptics_enable_hpwr_vreg(chip, false);
	if (rc < 0)
		dev_err(chip->dev, "disable hpwr_vreg failed, rc=%d\n");

	return rc;
}

static void haptics_set_gain(struct input_dev *dev, u16 gain)
@@ -2073,7 +2205,7 @@ static void haptics_set_gain(struct input_dev *dev, u16 gain)
	struct haptics_chip *chip = input_get_drvdata(dev);
	struct haptics_hw_config *config = &chip->config;
	struct haptics_play_info *play = &chip->play;
	u32 vmax_mv;
	u32 vmax_mv, amplitude;

	if (gain == 0)
		return;
@@ -2081,6 +2213,20 @@ static void haptics_set_gain(struct input_dev *dev, u16 gain)
	if (gain > 0x7fff)
		gain = 0x7fff;

	dev_dbg(chip->dev, "Set gain: %#x\n", gain);

	/* scale amplitude when playing in DIRECT_PLAY mode */
	if (chip->play.pattern_src == DIRECT_PLAY) {
		amplitude = get_direct_play_max_amplitude(chip);
		amplitude *= gain;
		amplitude /= 0x7fff;

		dev_dbg(chip->dev, "Set amplitude: %#x\n", amplitude);
		haptics_set_direct_play(chip, (u8)amplitude);
		return;
	}

	/* scale Vmax when playing in other modes */
	vmax_mv = config->vmax_mv;
	if (play->effect)
		vmax_mv = play->effect->vmax_mv;
@@ -3347,6 +3493,38 @@ static int haptics_get_revision(struct haptics_chip *chip)
	return 0;
}

static int haptics_parse_hpwr_vreg_dt(struct haptics_chip *chip)
{
	struct device_node *node = chip->dev->of_node;
	int rc;

	if (!of_find_property(node, "qcom,hpwr-supply", NULL))
		return 0;

	chip->hpwr_vreg = devm_regulator_get(chip->dev, "qcom,hpwr");
	if (IS_ERR(chip->hpwr_vreg)) {
		rc = PTR_ERR(chip->hpwr_vreg);
		if (rc != -EPROBE_DEFER)
			dev_err(chip->dev, "Failed to get qcom,hpwr-supply, rc=%d\n",
					rc);
		return rc;
	}

	rc = of_property_read_u32(node, "qcom,hpwr-voltage-mv",
			&chip->hpwr_voltage_mv);
	if (rc < 0) {
		dev_err(chip->dev, "Failed to read qcom,hpwr-voltage-mv, rc=%d\n",
				rc);
		return rc;
	}

	if (chip->hpwr_voltage_mv == 0 ||
			chip->hpwr_voltage_mv > NON_HBOOST_MAX_VMAX_MV)
		return -EINVAL;

	return 0;
}

static int haptics_parse_dt(struct haptics_chip *chip)
{
	struct haptics_hw_config *config = &chip->config;
@@ -3355,6 +3533,10 @@ static int haptics_parse_dt(struct haptics_chip *chip)
	const __be32 *addr;
	int rc = 0, tmp;

	rc = haptics_parse_hpwr_vreg_dt(chip);
	if (rc < 0)
		return rc;

	if (of_find_property(node, "nvmem-cells", NULL)) {
		chip->cl_brake_nvmem = devm_nvmem_cell_get(chip->dev,
						"hap_cl_brake");
@@ -3619,9 +3801,24 @@ static int haptics_pbs_trigger_isc_config(struct haptics_chip *chip)

#define MAX_SWEEP_STEPS		5
#define MAX_IMPEDANCE_MOHM	40000
#define MIN_ISC_MA		250
#define MIN_DUTY_MILLI_PCT	0
#define MAX_DUTY_MILLI_PCT	100000
#define LRA_CONFIG_REGS		3
static u32 get_lra_impedance_capable_max(struct haptics_chip *chip)
{
	u32 mohms = MAX_IMPEDANCE_MOHM;

	if (chip->clamp_at_5v)
		mohms = MAX_IMPEDANCE_MOHM / 2;

	if (chip->hpwr_vreg)
		mohms = (chip->hpwr_voltage_mv * 1000) / MIN_ISC_MA;

	dev_dbg(chip->dev, "LRA impedance capable max: %u mohms\n", mohms);
	return mohms;
}

static int haptics_detect_lra_impedance(struct haptics_chip *chip)
{
	int rc, i;
@@ -3633,7 +3830,7 @@ static int haptics_detect_lra_impedance(struct haptics_chip *chip)
	struct haptics_reg_info backup[LRA_CONFIG_REGS];
	u8 val;
	u32 duty_milli_pct, low_milli_pct, high_milli_pct;
	u32 amplitude, lra_min_mohms, lra_max_mohms;
	u32 amplitude, lra_min_mohms, lra_max_mohms, capability_mohms;

	if (chip->cfg_revision == HAP_CFG_V1) {
		dev_dbg(chip->dev, "HAP_CFG V1.0 doesn't support impedance detection\n");
@@ -3662,6 +3859,10 @@ static int haptics_detect_lra_impedance(struct haptics_chip *chip)
			goto restore;
	}

	rc = haptics_enable_hpwr_vreg(chip, true);
	if (rc < 0)
		goto restore;

	low_milli_pct = MIN_DUTY_MILLI_PCT;
	high_milli_pct = MAX_DUTY_MILLI_PCT;
	/* Sweep duty cycle using binary approach */
@@ -3704,11 +3905,12 @@ static int haptics_detect_lra_impedance(struct haptics_chip *chip)
		usleep_range(4000, 5000);
	}

	lra_min_mohms = low_milli_pct * MAX_IMPEDANCE_MOHM / 100000;
	lra_max_mohms = high_milli_pct * MAX_IMPEDANCE_MOHM / 100000;
	capability_mohms = get_lra_impedance_capable_max(chip);
	lra_min_mohms = low_milli_pct * capability_mohms / 100000;
	lra_max_mohms = high_milli_pct * capability_mohms / 100000;
	if (lra_min_mohms == 0)
		dev_warn(chip->dev, "Short circuit detected!\n");
	else if (lra_max_mohms == MAX_IMPEDANCE_MOHM)
	else if (lra_max_mohms >= capability_mohms)
		dev_warn(chip->dev, "Open circuit detected!\n");
	else
		dev_dbg(chip->dev, "LRA impedance is between %u - %u mohms\n",
@@ -3716,9 +3918,14 @@ static int haptics_detect_lra_impedance(struct haptics_chip *chip)

	chip->config.lra_min_mohms = lra_min_mohms;
	chip->config.lra_max_mohms = lra_max_mohms;
	chip->config.lra_open_mohms = capability_mohms;
restore:
	/* Disable play in case it's not been disabled */
	haptics_enable_play(chip, false);
	rc = haptics_enable_hpwr_vreg(chip, false);
	if (rc < 0)
		return rc;

	/* Trigger PBS to restore 1500mA ISC setting */
	rc = haptics_pbs_trigger_isc_config(chip);
	if (rc < 0)
@@ -3739,7 +3946,8 @@ static int haptics_detect_lra_impedance(struct haptics_chip *chip)
static int haptics_detect_lra_frequency(struct haptics_chip *chip)
{
	int rc;
	u8 autores_cfg;
	u8 autores_cfg, amplitude;
	u32 vmax_mv = chip->config.vmax_mv;

	rc = haptics_read(chip, chip->cfg_addr_base,
			HAP_CFG_AUTORES_CFG_REG, &autores_cfg, 1);
@@ -3760,15 +3968,24 @@ static int haptics_detect_lra_frequency(struct haptics_chip *chip)
	if (rc < 0)
		goto restore;

	rc = haptics_set_vmax_mv(chip, chip->config.vmax_mv);
	rc = haptics_set_vmax_headroom_mv(chip, LRA_CALIBRATION_VMAX_HDRM_MV);
	if (rc < 0)
		goto restore;

	rc = haptics_set_vmax_headroom_mv(chip, LRA_CALIBRATION_VMAX_HDRM_MV);
	/* Fix Vmax to (hpwr_vreg_mv - hdrm_mv) in non-HBOOST regulator case */
	if (chip->hpwr_vreg)
		vmax_mv = chip->hpwr_voltage_mv - LRA_CALIBRATION_VMAX_HDRM_MV;

	rc = haptics_set_vmax_mv(chip, vmax_mv);
	if (rc < 0)
		goto restore;

	rc = haptics_set_direct_play(chip, DIRECT_PLAY_MAX_AMPLITUDE);
	amplitude = get_direct_play_max_amplitude(chip);
	rc = haptics_set_direct_play(chip, amplitude);
	if (rc < 0)
		goto restore;

	rc = haptics_enable_hpwr_vreg(chip, true);
	if (rc < 0)
		goto restore;

@@ -3793,6 +4010,10 @@ static int haptics_detect_lra_frequency(struct haptics_chip *chip)
restore:
	/* Disable play in case it's not been disabled */
	haptics_enable_play(chip, false);
	rc = haptics_enable_hpwr_vreg(chip, false);
	if (rc < 0)
		return rc;

	rc = haptics_write(chip, chip->cfg_addr_base,
			HAP_CFG_AUTORES_CFG_REG, &autores_cfg, 1);

@@ -3889,7 +4110,7 @@ static ssize_t lra_impedance_show(struct class *c,
		return -EINVAL;
	else if (chip->config.lra_min_mohms == 0)
		return scnprintf(buf, PAGE_SIZE, "%s\n", "Short circuit");
	else if (chip->config.lra_max_mohms == MAX_IMPEDANCE_MOHM)
	else if (chip->config.lra_max_mohms >= chip->config.lra_open_mohms)
		return scnprintf(buf, PAGE_SIZE, "%s\n", "Open circuit");
	else
		return scnprintf(buf, PAGE_SIZE, "%u ~ %u mohms\n",
@@ -4071,6 +4292,10 @@ static int haptics_suspend(struct device *dev)
			return rc;
	}

	rc = haptics_enable_hpwr_vreg(chip, false);
	if (rc < 0)
		return rc;

	return haptics_write(chip, chip->cfg_addr_base,
		HAP_CFG_EN_CTL_REG, &val, 1);
}