From cf23f6122f8ae38ffdb2fdd360f2f5b9577428e2 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Fri, 24 Jul 2020 11:01:48 +0800 Subject: [PATCH 1/3] input: qcom-hv-haptics: update RC_CLK_CAL_COUNT calculation RC_CLK_CAL_COUNT is the calibration count used in manual RC_CLK_CAL mode when playing FIFO patterns. For haptics module in PM8350B 2.0, there are new equations recommended to calculate RC_CLK_CAL_COUNT based on CAL_TLRA_CL_STS and LAST_GOOD_TLRA_CL_STS status to achieve better accuracy. Update the driver to support this. Change-Id: I983c1b1f284006847549d2b3d23a0c1039f8b4c1 Signed-off-by: Fenglin Wu --- drivers/input/misc/qcom-hv-haptics.c | 105 ++++++++++++++++++++------- 1 file changed, 77 insertions(+), 28 deletions(-) diff --git a/drivers/input/misc/qcom-hv-haptics.c b/drivers/input/misc/qcom-hv-haptics.c index fdb26327f295..d0b4f71c9267 100644 --- a/drivers/input/misc/qcom-hv-haptics.c +++ b/drivers/input/misc/qcom-hv-haptics.c @@ -411,6 +411,7 @@ struct haptics_hw_config { u32 cl_t_lra_us; u32 preload_effect; u32 fifo_empty_thresh; + u16 rc_clk_cal_count; enum drv_sig_shape drv_wf; bool is_erm; }; @@ -727,7 +728,7 @@ static int haptics_get_closeloop_lra_period_v1( struct haptics_chip *chip) { struct haptics_hw_config *config = &chip->config; - int rc; + int rc, freq_diff, f_lra, cl_f_lra; u8 val[2]; u32 tmp, step_ns; bool auto_res_cal_done; @@ -761,7 +762,25 @@ static int haptics_get_closeloop_lra_period_v1( tmp = ((val[0] & CAL_TLRA_CL_STS_MSB_MASK) << 8) | val[1]; config->cl_t_lra_us = (tmp * step_ns) / 1000; - return haptics_adjust_lra_period(chip, &config->cl_t_lra_us); + rc = haptics_adjust_lra_period(chip, &config->cl_t_lra_us); + if (rc < 0) + return rc; + + /* calculate RC_CLK_CAL_COUNT */ + if (!config->t_lra_us || !config->cl_t_lra_us) + return -EINVAL; + + f_lra = USEC_PER_SEC / config->t_lra_us; + if (!f_lra) + return -EINVAL; + + cl_f_lra = USEC_PER_SEC / config->cl_t_lra_us; + freq_diff = cl_f_lra - f_lra; + + /* RC_CLK_CAL_COUNT = 600*(1-(clk_adjustment/Fifo_pat_freq)) */ + config->rc_clk_cal_count = 600 - ((600 * freq_diff) / f_lra); + + return 0; } #define TLRA_AUTO_RES_ERR_NO_CAL_STEP_PSEC 1667000 @@ -822,12 +841,16 @@ static int haptics_get_closeloop_lra_period_v2( if (rc_clk_cal == CAL_RC_CLK_DISABLED_VAL && !auto_res_done) { /* TLRA_CL_ERR(us) = TLRA_CL_ERR_STS * 1.667 us */ tmp = tlra_cl_err_sts * TLRA_AUTO_RES_ERR_NO_CAL_STEP_PSEC; + dev_dbg(chip->dev, "tlra_cl_err_sts = %#x\n", tlra_cl_err_sts); + config->cl_t_lra_us = div_u64(tmp, 1000000); } else if (rc_clk_cal == CAL_RC_CLK_DISABLED_VAL && auto_res_done) { /* * CAL_TLRA_CL_STS_NO_CAL = CAL_TLRA_CL_STS * TLRA_AUTO_RES(us) = CAL_TLRA_CL_STS_NO_CAL * 3.333 us */ tmp = cal_tlra_cl_sts * TLRA_AUTO_RES_NO_CAL_STEP_PSEC; + dev_dbg(chip->dev, "cal_tlra_cl_sts = %#x\n", cal_tlra_cl_sts); + config->cl_t_lra_us = div_u64(tmp, 1000000); } else if (rc_clk_cal == CAL_RC_CLK_AUTO_VAL && !auto_res_done) { /* * CAL_TLRA_OL = CAL_TLRA_CL_STS; @@ -842,9 +865,26 @@ static int haptics_get_closeloop_lra_period_v2( return rc; tlra_ol = (val[0] & TLRA_OL_MSB_MASK) << 8 | val[1]; + dev_dbg(chip->dev, "tlra_ol = %#x, tlra_cl_err_sts = %#x, cal_tlra_cl_sts = %#x\n", + tlra_ol, tlra_cl_err_sts, cal_tlra_cl_sts); + tmp = tlra_cl_err_sts * tlra_ol; tmp *= TLRA_AUTO_RES_ERR_AUTO_CAL_STEP_PSEC; tmp = div_u64(tmp, cal_tlra_cl_sts); + config->cl_t_lra_us = div_u64(tmp, 1000000); + + /* calculate RC_CLK_CAL_COUNT */ + if (!config->t_lra_us || !config->cl_t_lra_us) + return -EINVAL; + /* + * RC_CLK_CAL_COUNT = 600 * (CAL_TLRA_OL / TLRA_OL) + * * (600 / 586) * (CL_T_TLRA_US / OL_T_LRA_US) + */ + tmp = 360000; + tmp *= cal_tlra_cl_sts * config->cl_t_lra_us; + tmp = div_u64(tmp, tlra_ol); + tmp = div_u64(tmp, 586); + config->rc_clk_cal_count = div_u64(tmp, config->t_lra_us); } else if (rc_clk_cal == CAL_RC_CLK_AUTO_VAL && auto_res_done) { /* * CAL_TLRA_CL_STS_W_CAL = CAL_TLRA_CL_STS; @@ -873,17 +913,34 @@ static int haptics_get_closeloop_lra_period_v2( last_good_tlra_cl_sts = ((val[0] & LAST_GOOD_TLRA_CL_MSB_MASK) << 8) | val[1]; + dev_dbg(chip->dev, "last_good_tlra_cl_sts = %#x, cal_tlra_cl_sts = %#x\n", + last_good_tlra_cl_sts, cal_tlra_cl_sts); + tmp = last_good_tlra_cl_sts * last_good_tlra_cl_sts; tmp *= TLRA_AUTO_RES_AUTO_CAL_STEP_PSEC; tmp = div_u64(tmp, cal_tlra_cl_sts); + config->cl_t_lra_us = div_u64(tmp, 1000000); + + /* calculate RC_CLK_CAL_COUNT */ + if (!config->t_lra_us || !config->cl_t_lra_us) + return -EINVAL; + + /* + * RC_CLK_CAL_COUNT = + * 600 * (CAL_TLRA_CL_STS_AUTO_CAL / LAST_GOOD_TLRA_CL_STS) + * * (600 / 293) * (CL_T_TLRA_US / OL_T_LRA_US) + */ + tmp = 360000; + tmp *= cal_tlra_cl_sts * config->cl_t_lra_us; + tmp = div_u64(tmp, last_good_tlra_cl_sts); + tmp = div_u64(tmp, 293); + config->rc_clk_cal_count = div_u64(tmp, config->t_lra_us); } else { dev_err(chip->dev, "Can't get close-loop LRA period in rc_clk_cal mode %u\n", rc_clk_cal); return -EINVAL; } - config->cl_t_lra_us = div_u64(tmp, 1000000); - return 0; } @@ -902,8 +959,9 @@ static int haptics_get_closeloop_lra_period(struct haptics_chip *chip) return rc; } - dev_dbg(chip->dev, "OL_TLRA %u us, CL_TLRA %u us\n", - chip->config.t_lra_us, chip->config.cl_t_lra_us); + dev_dbg(chip->dev, "OL_TLRA %u us, CL_TLRA %u us, RC_CLK_CAL_COUNT %#x\n", + chip->config.t_lra_us, chip->config.cl_t_lra_us, + chip->config.rc_clk_cal_count); return 0; } @@ -1259,26 +1317,17 @@ static int haptics_get_available_fifo_memory(struct haptics_chip *chip) return available; } -static int haptics_adjust_rc_clk(struct haptics_chip *chip) +static int haptics_set_manual_rc_clk_cal(struct haptics_chip *chip) { - int rc, freq_diff, cal_count, f_lra, cl_f_lra; + int rc; + u16 cal_count = chip->config.rc_clk_cal_count; u8 val[2]; - if (!chip->config.t_lra_us || !chip->config.cl_t_lra_us) - return -EINVAL; + if (cal_count == 0) { + dev_dbg(chip->dev, "Ignore setting RC_CLK_CAL_COUNT\n"); + return 0; + } - f_lra = USEC_PER_SEC / chip->config.t_lra_us; - if (!f_lra) - return -EINVAL; - - cl_f_lra = USEC_PER_SEC / chip->config.cl_t_lra_us; - freq_diff = cl_f_lra - f_lra; - - /* RC_CLK_CAL_COUNT = 600*(1-(clk_adjustment/Fifo_pat_freq)) */ - cal_count = 600 - ((600 * freq_diff) / f_lra); - dev_dbg(chip->dev, "RC clock calibration count:%#x\n", cal_count); - - /* Set FIFO pattern frequency adjustment */ val[0] = (cal_count >> 8) & RC_CLK_CAL_COUNT_MSB_MASK; val[1] = cal_count & RC_CLK_CAL_COUNT_LSB_MASK; rc = haptics_write(chip, chip->cfg_addr_base, @@ -1288,7 +1337,8 @@ static int haptics_adjust_rc_clk(struct haptics_chip *chip) val[0] = CAL_RC_CLK_MANUAL_VAL << CAL_RC_CLK_SHIFT; return haptics_masked_write(chip, chip->cfg_addr_base, - HAP_CFG_CAL_EN_REG, CAL_RC_CLK_MASK, val[0]); + HAP_CFG_CAL_EN_REG, CAL_RC_CLK_MASK, + val[0]); } static int haptics_update_fifo_samples(struct haptics_chip *chip, @@ -1384,12 +1434,10 @@ static int haptics_set_fifo(struct haptics_chip *chip, struct fifo_cfg *fifo) return rc; if (fifo->period_per_s >= F_8KHZ) { - rc = haptics_adjust_rc_clk(chip); - if (rc < 0) { - dev_err(chip->dev, "RC CLK adjustment failed, rc=%d\n", - rc); + /* Set manual RC CLK CAL when playing FIFO */ + rc = haptics_set_manual_rc_clk_cal(chip); + if (rc < 0) return rc; - } } atomic_set(&status->written_done, 0); @@ -2055,6 +2103,7 @@ static int haptics_hw_init(struct haptics_chip *chip) if (rc < 0) return rc; + /* get calibrated close loop period */ rc = haptics_get_closeloop_lra_period(chip); if (rc < 0) return rc; From 7d3ecfd796b7ebb803540accc3f9442f56655f5e Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Mon, 27 Jul 2020 12:11:16 +0800 Subject: [PATCH 2/3] input: qcom-hv-haptics: read CAL_TLRA_CL_STS from SDAM after boot up During LRA frequency calibration, reading CAL_TLRA_CL_STS has to be done before de-asserting play. In the boot up LRA frequency calibration sequence, CAL_TLRA_CL_STS was read out and stored in SDAM module registers by the bootloader. Later, HLOS haptics driver can read it from there and use it for calculating LRA frequency. This boot up LRA frequency calibration sequence is only available for PM8350B 2.0 chip. Update the driver to support this. Change-Id: I0b81e79bad57160f9c79e01151e2d4060b4bbd41 Signed-off-by: Fenglin Wu --- drivers/input/misc/qcom-hv-haptics.c | 50 +++++++++++++++++++--------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/drivers/input/misc/qcom-hv-haptics.c b/drivers/input/misc/qcom-hv-haptics.c index d0b4f71c9267..533a893b5159 100644 --- a/drivers/input/misc/qcom-hv-haptics.c +++ b/drivers/input/misc/qcom-hv-haptics.c @@ -34,7 +34,7 @@ #define TLRA_CL_ERR_MSB_MASK GENMASK(4, 0) /* STATUS_DATA_MSB definition in V1 while MOD_STATUS_SEL is 5 */ #define FIFO_REAL_TIME_FILL_STATUS_MASK_V1 GENMASK(6, 0) -/* STATUS DATA_MSB definition in V2 while MOD_STATUS_SEL is 5 */ +/* 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 HAP_CFG_STATUS_DATA_LSB_REG 0x0A @@ -783,12 +783,16 @@ static int haptics_get_closeloop_lra_period_v1( return 0; } +/* The offset of SDAM register which saves STATUS_DATA_MSB value */ +#define HAP_STATUS_DATA_MSB_SDAM_OFFSET 0x46 + +/* constant definitions for calculating TLRA */ #define TLRA_AUTO_RES_ERR_NO_CAL_STEP_PSEC 1667000 #define TLRA_AUTO_RES_NO_CAL_STEP_PSEC 3333000 #define TLRA_AUTO_RES_ERR_AUTO_CAL_STEP_PSEC 1627700 #define TLRA_AUTO_RES_AUTO_CAL_STEP_PSEC 813850 static int haptics_get_closeloop_lra_period_v2( - struct haptics_chip *chip) + struct haptics_chip *chip, bool in_boot) { struct haptics_hw_config *config = &chip->config; u16 cal_tlra_cl_sts, tlra_cl_err_sts, tlra_ol, last_good_tlra_cl_sts; @@ -805,16 +809,31 @@ static int haptics_get_closeloop_lra_period_v2( rc_clk_cal = ((val[0] & CAL_RC_CLK_MASK) >> CAL_RC_CLK_SHIFT); /* read auto resonance calibration result */ - val[0] = MOD_STATUS_SEL_CAL_TLRA_CL_STS_VAL; - rc = haptics_write(chip, chip->cfg_addr_base, - HAP_CFG_MOD_STATUS_SEL_REG, val, 1); - if (rc < 0) - return rc; + if (in_boot) { + if (chip->hap_cfg_nvmem == NULL) { + dev_dbg(chip->dev, "nvmem device for hap_cfg is not defined\n"); + return -EINVAL; + } - rc = haptics_read(chip, chip->cfg_addr_base, - HAP_CFG_STATUS_DATA_MSB_REG, val, 2); - if (rc < 0) - return rc; + rc = nvmem_device_read(chip->hap_cfg_nvmem, + HAP_STATUS_DATA_MSB_SDAM_OFFSET, 2, val); + if (rc < 0) { + dev_err(chip->dev, "read SDAM %#x failed, rc=%d\n", + HAP_STATUS_DATA_MSB_SDAM_OFFSET, rc); + return rc; + } + } else { + val[0] = MOD_STATUS_SEL_CAL_TLRA_CL_STS_VAL; + rc = haptics_write(chip, chip->cfg_addr_base, + HAP_CFG_MOD_STATUS_SEL_REG, val, 1); + if (rc < 0) + return rc; + + rc = haptics_read(chip, chip->cfg_addr_base, + HAP_CFG_STATUS_DATA_MSB_REG, val, 2); + if (rc < 0) + return rc; + } auto_res_done = !!(val[0] & AUTO_RES_CAL_DONE_BIT); cal_tlra_cl_sts = @@ -944,14 +963,15 @@ static int haptics_get_closeloop_lra_period_v2( return 0; } -static int haptics_get_closeloop_lra_period(struct haptics_chip *chip) +static int haptics_get_closeloop_lra_period(struct haptics_chip *chip, + bool in_boot) { int rc = 0; if (chip->ptn_revision == HAP_PTN_V1) rc = haptics_get_closeloop_lra_period_v1(chip); else - rc = haptics_get_closeloop_lra_period_v2(chip); + rc = haptics_get_closeloop_lra_period_v2(chip, in_boot); if (rc < 0) { dev_err(chip->dev, "get close loop T LRA failed, rc=%d\n", @@ -2104,7 +2124,7 @@ static int haptics_hw_init(struct haptics_chip *chip) return rc; /* get calibrated close loop period */ - rc = haptics_get_closeloop_lra_period(chip); + rc = haptics_get_closeloop_lra_period(chip, true); if (rc < 0) return rc; @@ -3536,7 +3556,7 @@ static int haptics_start_lra_calibration(struct haptics_chip *chip) /* wait for ~150ms to get the LRA calibration result */ usleep_range(150000, 155000); - rc = haptics_get_closeloop_lra_period(chip); + rc = haptics_get_closeloop_lra_period(chip, false); if (rc < 0) goto restore; From 880117aa48a3feb74a19097fab7b1c2201b4dd2e Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Wed, 5 Aug 2020 16:45:18 +0800 Subject: [PATCH 3/3] input: qcom-hv-haptics: toggle CAL_EN mode if HBST is in open loop When RC_CLK_CAL_EN is set in auto mode while haptics boost is working in open loop, the first cycle of the vibration would be played incorrectly because the haptics module couldn't get enough clock count before the play gets triggered. Fix this by toggling the RC clock calibration mode from disabled to auto mode. Change-Id: I80b3c48b9bb508b12841a679eafa2c618771edf2 Signed-off-by: Fenglin Wu --- drivers/input/misc/qcom-hv-haptics.c | 53 ++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/input/misc/qcom-hv-haptics.c b/drivers/input/misc/qcom-hv-haptics.c index 533a893b5159..da78067d5d46 100644 --- a/drivers/input/misc/qcom-hv-haptics.c +++ b/drivers/input/misc/qcom-hv-haptics.c @@ -217,6 +217,14 @@ #define HAP_BOOST_V0P0 0x0000 #define HAP_BOOST_V0P1 0x0001 +#define HAP_BOOST_HW_CTRL_FOLLOW_REG 0x41 +#define FOLLOW_HW_EN_BIT BIT(7) +#define FOLLOW_HW_CCM_BIT BIT(6) +#define FOLLOW_HW_VSET_BIT BIT(5) + +#define HAP_BOOST_VREG_EN_REG 0x46 +#define VREG_EN_BIT BIT(7) + #define HAP_BOOST_V0P0_CLAMP_REG 0xF1 #define HAP_BOOST_V0P1_CLAMP_REG 0x70 #define CLAMP_5V_BIT BIT(0) @@ -1090,6 +1098,24 @@ static int haptics_boost_vreg_enable(struct haptics_chip *chip, bool en) return rc; } +static bool is_boost_vreg_enabled_in_open_loop(struct haptics_chip *chip) +{ + int rc; + u8 val; + + rc = haptics_read(chip, chip->hbst_addr_base, + HAP_BOOST_HW_CTRL_FOLLOW_REG, &val, 1); + if (!rc && !(val & FOLLOW_HW_EN_BIT)) { + rc = haptics_read(chip, chip->hbst_addr_base, + HAP_BOOST_VREG_EN_REG, &val, 1); + if (!rc && (val & VREG_EN_BIT)) + return true; + } + + dev_dbg(chip->dev, "HBoost is not enabled in open loop condition\n"); + return false; +} + static int haptics_enable_play(struct haptics_chip *chip, bool en) { struct haptics_play_info *play = &chip->play; @@ -1103,6 +1129,33 @@ static int haptics_enable_play(struct haptics_chip *chip, bool en) HAP_CFG_FAULT_CLR_REG, &val, 1); if (rc < 0) return rc; + + /* + * Toggle RC_CLK_CAL_EN if it's in auto mode and + * haptics boost is working in open loop + */ + 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)) { + rc = haptics_masked_write(chip, chip->cfg_addr_base, + HAP_CFG_CAL_EN_REG, CAL_RC_CLK_MASK, + CAL_RC_CLK_DISABLED_VAL); + if (rc < 0) + return rc; + + rc = haptics_masked_write(chip, chip->cfg_addr_base, + HAP_CFG_CAL_EN_REG, CAL_RC_CLK_MASK, + CAL_RC_CLK_AUTO_VAL); + if (rc < 0) + return rc; + + dev_dbg(chip->dev, "Toggle CAL_EN in open-loop-VREG playing\n"); + } } val = play->pattern_src;