From 44ec5b55d0f2d52f431476de9715bdf942514d93 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Mon, 10 Jan 2022 11:05:55 +0800 Subject: [PATCH] input: qcom-hv-haptics: reset FIFO play logic when hBoost is busy Currently, when waiting for hBoost ready times out, error code -EBUSY is returned. In addition to that, reset the FIFO play logic so that the following FIFO requests can still be served. Meanwhile, add 100us before updating HAPTICS_EN for hBoost to have enough time to handle its power transition as per the hardware recommendation. Change-Id: Iebfc98b589bda747e4c2b6fdf6ff78d2f46ece5d Signed-off-by: Fenglin Wu --- drivers/input/misc/qcom-hv-haptics.c | 100 ++++++++++++++++----------- 1 file changed, 61 insertions(+), 39 deletions(-) diff --git a/drivers/input/misc/qcom-hv-haptics.c b/drivers/input/misc/qcom-hv-haptics.c index d61ddbb0f797..05b9ab328b81 100644 --- a/drivers/input/misc/qcom-hv-haptics.c +++ b/drivers/input/misc/qcom-hv-haptics.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -1792,10 +1792,17 @@ static int haptics_toggle_module_enable(struct haptics_chip *chip) { int rc; + /* + * Updating HAPTICS_EN would vote hBoost enable status. Add 100us + * delay before updating HAPTICS_EN for hBoost to have enough time + * to handle its power transition. + */ + usleep_range(100, 101); rc = haptics_module_enable(chip, false); if (rc < 0) return rc; + usleep_range(100, 101); return haptics_module_enable(chip, true); } @@ -2258,6 +2265,46 @@ static u8 get_direct_play_max_amplitude(struct haptics_chip *chip) return (u8)amplitude; } +static int haptics_stop_fifo_play(struct haptics_chip *chip) +{ + int rc; + u8 val; + + if (atomic_read(&chip->play.fifo_status.is_busy) == 0) { + dev_dbg(chip->dev, "FIFO playing is not in progress\n"); + return 0; + } + + rc = haptics_enable_play(chip, false); + if (rc < 0) + return rc; + + /* restore FIFO play rate back to T_LRA */ + rc = haptics_set_fifo_playrate(chip, T_LRA); + if (rc < 0) + return rc; + + haptics_fifo_empty_irq_config(chip, false); + kvfree(chip->custom_effect->fifo->samples); + chip->custom_effect->fifo->samples = NULL; + + atomic_set(&chip->play.fifo_status.is_busy, 0); + + /* + * All other playing modes would use AUTO mode RC + * calibration except FIFO streaming mode, so restore + * back to AUTO RC calibration after FIFO playing. + */ + val = CAL_RC_CLK_AUTO_VAL << CAL_RC_CLK_SHIFT; + rc = haptics_masked_write(chip, chip->cfg_addr_base, + HAP_CFG_CAL_EN_REG, CAL_RC_CLK_MASK, val); + if (rc < 0) + return rc; + + dev_dbg(chip->dev, "stopped FIFO playing successfully\n"); + return 0; +} + static int haptics_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old) { @@ -2327,46 +2374,21 @@ static int haptics_upload_effect(struct input_dev *dev, return rc; } - return haptics_wait_hboost_ready(chip); -} - -static int haptics_stop_fifo_play(struct haptics_chip *chip) -{ - int rc; - u8 val; - - if (atomic_read(&chip->play.fifo_status.is_busy) == 0) { - dev_dbg(chip->dev, "FIFO playing is not in progress\n"); - return 0; + rc = haptics_wait_hboost_ready(chip); + if (rc < 0 && chip->play.pattern_src == FIFO) { + /* + * Call haptics_stop_fifo_play(chip) explicitly if hBoost is + * not ready for the FIFO play. This drops current FIFO play + * but it restores the SW back to initial status so that the + * following FIFO play requests can still be served. + */ + dev_dbg(chip->dev, "stop FIFO play explicitly to restore SW status\n"); + mutex_lock(&chip->play.lock); + haptics_stop_fifo_play(chip); + mutex_unlock(&chip->play.lock); + return rc; } - rc = haptics_enable_play(chip, false); - if (rc < 0) - return rc; - - /* restore FIFO play rate back to T_LRA */ - rc = haptics_set_fifo_playrate(chip, T_LRA); - if (rc < 0) - return rc; - - haptics_fifo_empty_irq_config(chip, false); - kvfree(chip->custom_effect->fifo->samples); - chip->custom_effect->fifo->samples = NULL; - - atomic_set(&chip->play.fifo_status.is_busy, 0); - - /* - * All other playing modes would use AUTO mode RC - * calibration except FIFO streaming mode, so restore - * back to AUTO RC calibration after FIFO playing. - */ - val = CAL_RC_CLK_AUTO_VAL << CAL_RC_CLK_SHIFT; - rc = haptics_masked_write(chip, chip->cfg_addr_base, - HAP_CFG_CAL_EN_REG, CAL_RC_CLK_MASK, val); - if (rc < 0) - return rc; - - dev_dbg(chip->dev, "stopped FIFO playing successfully\n"); return 0; }