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: Fenglin Wu <fenglinw@codeaurora.org>
This commit is contained in:
Fenglin Wu 2020-10-26 09:50:44 +08:00 committed by David Collins
parent 19152cdd28
commit f1cd3fe57e

View File

@ -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)
{
int rc;
if (chip->hpwr_vreg == NULL || chip->hpwr_vreg_enabled == en)
return 0;
if (en) {
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)
{
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 ((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);
if (rc < 0)
goto restore;
rc = haptics_set_vmax_headroom_mv(chip, LRA_CALIBRATION_VMAX_HDRM_MV);
if (rc < 0)
goto restore;
rc = haptics_set_direct_play(chip, DIRECT_PLAY_MAX_AMPLITUDE);
/* 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;
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);
}