From 66cd9cf31c2e2be8571aebc1a30203cddc381c31 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Mon, 14 Dec 2020 11:00:04 +0800 Subject: [PATCH 1/2] input: qcom-hv-haptics: keep FORCE_VREG_RDY always set in non-HBoost case FORCE_VREG_RDY bit can be always set when non-HBoost regulator is used and don't clear it when stopping play in non-HBoost case. Also set this bit in driver initialization in non-HBoost case so that swr-haptics driver can take the advantage of triggering SWR play without setting this bit. Change-Id: I6283396d9d5a4f0b87d87932d6db2d8e7bb7a623 Signed-off-by: Fenglin Wu --- drivers/input/misc/qcom-hv-haptics.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/input/misc/qcom-hv-haptics.c b/drivers/input/misc/qcom-hv-haptics.c index ef7cf4b8a784..23bfbbaaf0aa 100644 --- a/drivers/input/misc/qcom-hv-haptics.c +++ b/drivers/input/misc/qcom-hv-haptics.c @@ -1205,13 +1205,12 @@ static int haptics_enable_hpwr_vreg(struct haptics_chip *chip, bool en) static int haptics_open_loop_drive_config(struct haptics_chip *chip, bool en) { - int rc; + int rc = 0; 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); @@ -1242,11 +1241,10 @@ static int haptics_open_loop_drive_config(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; + } else if (chip->hpwr_vreg == NULL) { rc = haptics_masked_write(chip, chip->cfg_addr_base, HAP_CFG_VSET_CFG_REG, - FORCE_VREG_RDY_BIT, val); + FORCE_VREG_RDY_BIT, 0); } return rc; @@ -2335,6 +2333,15 @@ static int haptics_hw_init(struct haptics_chip *chip) if (rc < 0) return rc; + /* Force VREG_RDY if non-HBoost is used for powering haptics */ + if (chip->hpwr_vreg) { + 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; + } + if (config->is_erm) return 0; From a2451a5b29b431844bd7ea9b6b9eed2c30f78fb7 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Mon, 14 Dec 2020 10:14:16 +0800 Subject: [PATCH 2/2] input: qcom-hv-haptics: toggle HAPTICS_EN bit before playing FIFO When FIFO samples are played back to back along with SWR mode, there is a chance that FIFO samples won't get flushed out if they're not fully played before FIFO mode is stopped. When this happens, FIFO samples gets accumulated leading to overflow after which FIFO mode stops working. Only way to recover from this is to toggle HAPTICS_EN_BIT before starting FIFO mode playing again. While at it, add logs to print out FIFO real time fill status which is helpful for debugging. Change-Id: I07cd9ac34ad5ccfe7011850db554ba727f568482 Signed-off-by: Fenglin Wu --- drivers/input/misc/qcom-hv-haptics.c | 77 +++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 14 deletions(-) diff --git a/drivers/input/misc/qcom-hv-haptics.c b/drivers/input/misc/qcom-hv-haptics.c index 23bfbbaaf0aa..43de43dc22b0 100644 --- a/drivers/input/misc/qcom-hv-haptics.c +++ b/drivers/input/misc/qcom-hv-haptics.c @@ -41,6 +41,8 @@ #define FIFO_REAL_TIME_FILL_STATUS_MASK_V1 GENMASK(6, 0) /* STATUS_DATA_MSB definition in V2 while MOD_STATUS_SEL is 5 */ #define FIFO_REAL_TIME_FILL_STATUS_MSB_MASK_V2 GENMASK(1, 0) +#define FIFO_EMPTY_FLAG_BIT_V2 BIT(6) +#define FIFO_FULL_FLAG_BIT_V2 BIT(5) #define HAP_CFG_STATUS_DATA_LSB_REG 0x0A /* STATUS_DATA_MSB definition while MOD_STATUS_SEL is 0 */ @@ -1447,11 +1449,11 @@ static int haptics_update_fifo_sample_v2(struct haptics_chip *chip, return 0; } -static int haptics_get_available_fifo_memory(struct haptics_chip *chip) +static int haptics_get_fifo_fill_status(struct haptics_chip *chip, u32 *fill) { int rc; u8 val[2]; - u32 fill, available; + bool empty = false, full = false; if (chip->ptn_revision == HAP_PTN_V1) { val[0] = MOD_STATUS_SEL_FIFO_FILL_STATUS_VAL; @@ -1465,7 +1467,7 @@ static int haptics_get_available_fifo_memory(struct haptics_chip *chip) if (rc < 0) return rc; - fill = val[0] & FIFO_REAL_TIME_FILL_STATUS_MASK_V1; + *fill = val[0] & FIFO_REAL_TIME_FILL_STATUS_MASK_V1; } else { val[0] = MOD_STATUS_XT_V2_FIFO_FILL_STATUS_VAL; rc = haptics_write(chip, chip->cfg_addr_base, @@ -1484,10 +1486,25 @@ static int haptics_get_available_fifo_memory(struct haptics_chip *chip) if (rc < 0) return rc; - fill = ((val[0] & FIFO_REAL_TIME_FILL_STATUS_MSB_MASK_V2) + *fill = ((val[0] & FIFO_REAL_TIME_FILL_STATUS_MSB_MASK_V2) << 8) | val[1]; + empty = !!(val[0] & FIFO_EMPTY_FLAG_BIT_V2); + full = !!(val[0] & FIFO_FULL_FLAG_BIT_V2); } + dev_dbg(chip->dev, "filled=%d, full=%d, empty=%d\n", *fill, full, empty); + return 0; +} + +static int haptics_get_available_fifo_memory(struct haptics_chip *chip) +{ + int rc; + u32 fill, available; + + rc = haptics_get_fifo_fill_status(chip, &fill); + if (rc < 0) + return rc; + if (fill > MAX_FIFO_SAMPLES(chip)) { dev_err(chip->dev, "Filled FIFO number %d exceed the max %d\n", fill, MAX_FIFO_SAMPLES(chip)); @@ -1599,6 +1616,33 @@ static int haptics_set_fifo_empty_threshold(struct haptics_chip *chip, return rc; } +static int haptics_module_enable(struct haptics_chip *chip, bool enable) +{ + u8 val; + int rc; + + val = enable ? HAPTICS_EN_BIT : 0; + rc = haptics_write(chip, chip->cfg_addr_base, + HAP_CFG_EN_CTL_REG, &val, 1); + if (rc < 0) + return rc; + + dev_dbg(chip->dev, "haptics module %s\n", + enable ? "enabled" : "disabled"); + return 0; +} + +static int haptics_toggle_module_enable(struct haptics_chip *chip) +{ + int rc; + + rc = haptics_module_enable(chip, false); + if (rc < 0) + return rc; + + return haptics_module_enable(chip, true); +} + static int haptics_set_fifo(struct haptics_chip *chip, struct fifo_cfg *fifo) { struct fifo_play_status *status = &chip->play.fifo_status; @@ -1732,6 +1776,13 @@ static int haptics_load_predefined_effect(struct haptics_chip *chip, return -EINVAL; play->effect = effect; + if (play->pattern_src == FIFO) { + /* Toggle HAPTICS_EN for a clear start point of FIFO playing */ + rc = haptics_toggle_module_enable(chip); + if (rc < 0) + return rc; + } + /* Clamp VMAX for different vibration strength */ rc = haptics_set_vmax_mv(chip, play->vmax_mv); if (rc < 0) @@ -1910,6 +1961,11 @@ static int haptics_load_custom_effect(struct haptics_chip *chip, play->effect = chip->custom_effect; play->brake = NULL; play->vmax_mv = (magnitude * chip->custom_effect->vmax_mv) / 0x7fff; + /* Toggle HAPTICS_EN for a clear start point of FIFO playing */ + rc = haptics_toggle_module_enable(chip); + if (rc < 0) + goto cleanup; + rc = haptics_set_vmax_mv(chip, play->vmax_mv); if (rc < 0) goto cleanup; @@ -2411,11 +2467,8 @@ static irqreturn_t fifo_empty_irq_handler(int irq, void *data) if (rc < 0) return IRQ_HANDLED; - if (!(val & FIFO_EMPTY_BIT)) { - dev_dbg(chip->dev, "Ignore spurious/falling IRQ, INT_RT_STS = %#x\n", - val); + if (!(val & FIFO_EMPTY_BIT)) return IRQ_HANDLED; - } mutex_lock(&chip->play.lock); if (atomic_read(&chip->play.fifo_status.written_done) == 1) { @@ -4293,7 +4346,6 @@ static int haptics_suspend(struct device *dev) { struct haptics_chip *chip = dev_get_drvdata(dev); struct haptics_play_info *play = &chip->play; - u8 val = 0; int rc; if (chip->cfg_revision == HAP_CFG_V1) @@ -4326,20 +4378,17 @@ static int haptics_suspend(struct device *dev) if (rc < 0) return rc; - return haptics_write(chip, chip->cfg_addr_base, - HAP_CFG_EN_CTL_REG, &val, 1); + return haptics_module_enable(chip, false); } static int haptics_resume(struct device *dev) { struct haptics_chip *chip = dev_get_drvdata(dev); - u8 val = HAPTICS_EN_BIT; if (chip->cfg_revision == HAP_CFG_V1) return 0; - return haptics_write(chip, chip->cfg_addr_base, - HAP_CFG_EN_CTL_REG, &val, 1); + return haptics_module_enable(chip, true); } #endif