diff --git a/drivers/input/misc/qcom-hv-haptics.c b/drivers/input/misc/qcom-hv-haptics.c index dace2b08e7a0..ff16832173c8 100644 --- a/drivers/input/misc/qcom-hv-haptics.c +++ b/drivers/input/misc/qcom-hv-haptics.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -543,6 +544,7 @@ struct haptics_chip { struct device_node *pbs_node; struct class hap_class; struct regulator *hpwr_vreg; + struct hrtimer hbst_off_timer; int fifo_empty_irq; u32 hpwr_voltage_mv; u32 effects_count; @@ -561,6 +563,7 @@ struct haptics_chip { bool clamp_at_5v; bool hpwr_vreg_enabled; bool is_hv_haptics; + bool hboost_enabled; }; struct haptics_reg_info { @@ -1218,6 +1221,9 @@ static int haptics_boost_vreg_enable(struct haptics_chip *chip, bool en) return 0; } + if (chip->hboost_enabled == en) + return 0; + val = en ? HAP_VREG_ON_VAL : HAP_VREG_OFF_VAL; rc = nvmem_device_write(chip->hap_cfg_nvmem, PBS_ARG_REG, 1, &val); @@ -1230,11 +1236,14 @@ static int haptics_boost_vreg_enable(struct haptics_chip *chip, bool en) val = PBS_TRIG_SET_VAL; rc = nvmem_device_write(chip->hap_cfg_nvmem, PBS_TRIG_SET_REG, 1, &val); - if (rc < 0) + if (rc < 0) { dev_err(chip->dev, "Write SDAM %#x failed, rc=%d\n", PBS_TRIG_SET_REG, rc); + return rc; + } - return rc; + chip->hboost_enabled = en; + return 0; } static bool is_swr_play_enabled(struct haptics_chip *chip) @@ -1286,6 +1295,14 @@ static int haptics_wait_hboost_ready(struct haptics_chip *chip) if (!(chip->wa_flags & SW_CTRL_HBST)) return 0; + + if ((hrtimer_get_remaining(&chip->hbst_off_timer) > 0) || + hrtimer_active(&chip->hbst_off_timer)) { + hrtimer_cancel(&chip->hbst_off_timer); + dev_dbg(chip->dev, "hboost is still on, ignore\n"); + return 0; + } + /* * Wait ~20ms until hBoost is ready, otherwise * bail out and return -EBUSY @@ -1425,6 +1442,7 @@ static int haptics_open_loop_drive_config(struct haptics_chip *chip, bool en) return rc; } +#define BOOST_VREG_OFF_DELAY_SECONDS 2 static int haptics_enable_play(struct haptics_chip *chip, bool en) { struct haptics_play_info *play = &chip->play; @@ -1461,11 +1479,19 @@ static int haptics_enable_play(struct haptics_chip *chip, bool en) return rc; } - if (play->pattern_src == FIFO) { - rc = haptics_boost_vreg_enable(chip, en); - if (rc < 0) - dev_err(chip->dev, "Notify vreg %s failed, rc=%d\n", - en ? "enabling" : "disabling", rc); + if (chip->wa_flags & SW_CTRL_HBST) { + if (en) { + rc = haptics_boost_vreg_enable(chip, true); + if (rc < 0) { + dev_err(chip->dev, "Keep boost vreg on failed, rc=%d\n", + rc); + return rc; + } + } else { + hrtimer_start(&chip->hbst_off_timer, + ktime_set(BOOST_VREG_OFF_DELAY_SECONDS, 0), + HRTIMER_MODE_REL); + } } return rc; @@ -4758,6 +4784,21 @@ static bool is_swr_supported(struct haptics_chip *chip) return true; } +static enum hrtimer_restart haptics_disable_hbst_timer(struct hrtimer *timer) +{ + struct haptics_chip *chip = container_of(timer, + struct haptics_chip, hbst_off_timer); + int rc; + + rc = haptics_boost_vreg_enable(chip, false); + if (rc < 0) + dev_err(chip->dev, "disable boost vreg failed, rc=%d\n", rc); + else + dev_dbg(chip->dev, "boost vreg is disabled\n"); + + return HRTIMER_NORESTART; +} + static int haptics_probe(struct platform_device *pdev) { struct haptics_chip *chip; @@ -4819,6 +4860,8 @@ static int haptics_probe(struct platform_device *pdev) mutex_init(&chip->play.lock); disable_irq_nosync(chip->fifo_empty_irq); chip->fifo_empty_irq_en = false; + hrtimer_init(&chip->hbst_off_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + chip->hbst_off_timer.function = haptics_disable_hbst_timer; atomic_set(&chip->play.fifo_status.is_busy, 0); atomic_set(&chip->play.fifo_status.written_done, 0); @@ -4925,6 +4968,15 @@ static int haptics_suspend(struct device *dev) } mutex_unlock(&play->lock); + /* + * Cancel the hBoost turning off timer and disable + * hBoost if it's still enabled + */ + if (chip->wa_flags & SW_CTRL_HBST) { + hrtimer_cancel(&chip->hbst_off_timer); + haptics_boost_vreg_enable(chip, false); + } + rc = haptics_enable_hpwr_vreg(chip, false); if (rc < 0) return rc;