diff options
Diffstat (limited to 'drivers/soc/qcom/qpnp-haptic.c')
| -rw-r--r-- | drivers/soc/qcom/qpnp-haptic.c | 1246 |
1 files changed, 673 insertions, 573 deletions
diff --git a/drivers/soc/qcom/qpnp-haptic.c b/drivers/soc/qcom/qpnp-haptic.c index cf0b7ff25201..70cf11359e97 100644 --- a/drivers/soc/qcom/qpnp-haptic.c +++ b/drivers/soc/qcom/qpnp-haptic.c @@ -10,6 +10,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "haptic: %s: " fmt, __func__ + #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> @@ -25,21 +27,21 @@ #include <linux/qpnp/pwm.h> #include <linux/err.h> #include <linux/delay.h> +#include <linux/log2.h> +#include <linux/qpnp-misc.h> #include <linux/qpnp/qpnp-haptic.h> +#include <linux/qpnp/qpnp-revid.h> #include "../../staging/android/timed_output.h" -#define QPNP_IRQ_FLAGS (IRQF_TRIGGER_RISING | \ - IRQF_TRIGGER_FALLING | \ - IRQF_ONESHOT) - #define QPNP_HAP_STATUS(b) (b + 0x0A) #define QPNP_HAP_LRA_AUTO_RES_LO(b) (b + 0x0B) #define QPNP_HAP_LRA_AUTO_RES_HI(b) (b + 0x0C) #define QPNP_HAP_EN_CTL_REG(b) (b + 0x46) #define QPNP_HAP_EN_CTL2_REG(b) (b + 0x48) -#define QPNP_HAP_ACT_TYPE_REG(b) (b + 0x4C) -#define QPNP_HAP_WAV_SHAPE_REG(b) (b + 0x4D) -#define QPNP_HAP_PLAY_MODE_REG(b) (b + 0x4E) +#define QPNP_HAP_AUTO_RES_CTRL(b) (b + 0x4B) +#define QPNP_HAP_CFG1_REG(b) (b + 0x4C) +#define QPNP_HAP_CFG2_REG(b) (b + 0x4D) +#define QPNP_HAP_SEL_REG(b) (b + 0x4E) #define QPNP_HAP_LRA_AUTO_RES_REG(b) (b + 0x4F) #define QPNP_HAP_VMAX_REG(b) (b + 0x51) #define QPNP_HAP_ILIM_REG(b) (b + 0x52) @@ -59,37 +61,48 @@ #define QPNP_HAP_TEST2_REG(b) (b + 0xE3) #define QPNP_HAP_STATUS_BUSY 0x02 -#define QPNP_HAP_ACT_TYPE_MASK 0xFE +#define QPNP_HAP_ACT_TYPE_MASK BIT(0) #define QPNP_HAP_LRA 0x0 #define QPNP_HAP_ERM 0x1 -#define QPNP_HAP_AUTO_RES_MODE_MASK 0x8F +#define QPNP_HAP_PM660_HW_AUTO_RES_MODE_BIT BIT(3) +#define QPNP_HAP_AUTO_RES_MODE_MASK GENMASK(6, 4) #define QPNP_HAP_AUTO_RES_MODE_SHIFT 4 -#define QPNP_HAP_LRA_HIGH_Z_MASK 0xF3 -#define QPNP_HAP_LRA_HIGH_Z_SHIFT 2 -#define QPNP_HAP_LRA_RES_CAL_PER_MASK 0xFC -#define QPNP_HAP_RES_CAL_PERIOD_MIN 4 -#define QPNP_HAP_RES_CAL_PERIOD_MAX 32 -#define QPNP_HAP_PLAY_MODE_MASK 0xCF -#define QPNP_HAP_PLAY_MODE_SHFT 4 -#define QPNP_HAP_VMAX_MASK 0xC1 +#define QPNP_HAP_PM660_AUTO_RES_MODE_BIT BIT(7) +#define QPNP_HAP_PM660_AUTO_RES_MODE_SHIFT 7 +#define QPNP_HAP_PM660_CALIBRATE_DURATION_MASK GENMASK(6, 5) +#define QPNP_HAP_PM660_CALIBRATE_DURATION_SHIFT 5 +#define QPNP_HAP_PM660_QWD_DRIVE_DURATION_BIT BIT(4) +#define QPNP_HAP_PM660_QWD_DRIVE_DURATION_SHIFT 4 +#define QPNP_HAP_PM660_CALIBRATE_AT_EOP_BIT BIT(3) +#define QPNP_HAP_PM660_CALIBRATE_AT_EOP_SHIFT 3 +#define QPNP_HAP_PM660_LRA_ZXD_CAL_PERIOD_BIT GENMASK(2, 0) +#define QPNP_HAP_LRA_HIGH_Z_MASK GENMASK(3, 2) +#define QPNP_HAP_LRA_HIGH_Z_SHIFT 2 +#define QPNP_HAP_LRA_RES_CAL_PER_MASK GENMASK(1, 0) +#define QPNP_HAP_PM660_LRA_RES_CAL_PER_MASK GENMASK(2, 0) +#define QPNP_HAP_RES_CAL_PERIOD_MIN 4 +#define QPNP_HAP_RES_CAL_PERIOD_MAX 32 +#define QPNP_HAP_PM660_RES_CAL_PERIOD_MAX 256 +#define QPNP_HAP_WF_SOURCE_MASK GENMASK(5, 4) +#define QPNP_HAP_WF_SOURCE_SHIFT 4 +#define QPNP_HAP_VMAX_MASK GENMASK(5, 1) #define QPNP_HAP_VMAX_SHIFT 1 #define QPNP_HAP_VMAX_MIN_MV 116 #define QPNP_HAP_VMAX_MAX_MV 3596 -#define QPNP_HAP_ILIM_MASK 0xFE +#define QPNP_HAP_ILIM_MASK BIT(0) #define QPNP_HAP_ILIM_MIN_MV 400 #define QPNP_HAP_ILIM_MAX_MV 800 -#define QPNP_HAP_SC_DEB_MASK 0xF8 -#define QPNP_HAP_SC_DEB_SUB 2 +#define QPNP_HAP_SC_DEB_MASK GENMASK(2, 0) #define QPNP_HAP_SC_DEB_CYCLES_MIN 0 #define QPNP_HAP_DEF_SC_DEB_CYCLES 8 #define QPNP_HAP_SC_DEB_CYCLES_MAX 32 #define QPNP_HAP_SC_CLR 1 -#define QPNP_HAP_INT_PWM_MASK 0xFC +#define QPNP_HAP_INT_PWM_MASK GENMASK(1, 0) #define QPNP_HAP_INT_PWM_FREQ_253_KHZ 253 #define QPNP_HAP_INT_PWM_FREQ_505_KHZ 505 #define QPNP_HAP_INT_PWM_FREQ_739_KHZ 739 #define QPNP_HAP_INT_PWM_FREQ_1076_KHZ 1076 -#define QPNP_HAP_WAV_SHAPE_MASK 0xFE +#define QPNP_HAP_WAV_SHAPE_MASK BIT(0) #define QPNP_HAP_RATE_CFG1_MASK 0xFF #define QPNP_HAP_RATE_CFG2_MASK 0xF0 #define QPNP_HAP_RATE_CFG2_SHFT 8 @@ -97,9 +110,9 @@ #define QPNP_HAP_WAV_PLAY_RATE_US_MIN 0 #define QPNP_HAP_DEF_WAVE_PLAY_RATE_US 5715 #define QPNP_HAP_WAV_PLAY_RATE_US_MAX 20475 -#define QPNP_HAP_WAV_REP_MASK 0x8F -#define QPNP_HAP_WAV_S_REP_MASK 0xFC -#define QPNP_HAP_WAV_REP_SHFT 4 +#define QPNP_HAP_WAV_REP_MASK GENMASK(6, 4) +#define QPNP_HAP_WAV_S_REP_MASK GENMASK(1, 0) +#define QPNP_HAP_WAV_REP_SHIFT 4 #define QPNP_HAP_WAV_REP_MIN 1 #define QPNP_HAP_WAV_REP_MAX 128 #define QPNP_HAP_WAV_S_REP_MIN 1 @@ -107,13 +120,13 @@ #define QPNP_HAP_BRAKE_PAT_MASK 0x3 #define QPNP_HAP_ILIM_MIN_MA 400 #define QPNP_HAP_ILIM_MAX_MA 800 -#define QPNP_HAP_EXT_PWM_MASK 0xFC +#define QPNP_HAP_EXT_PWM_MASK GENMASK(1, 0) #define QPNP_HAP_EXT_PWM_FREQ_25_KHZ 25 #define QPNP_HAP_EXT_PWM_FREQ_50_KHZ 50 #define QPNP_HAP_EXT_PWM_FREQ_75_KHZ 75 #define QPNP_HAP_EXT_PWM_FREQ_100_KHZ 100 #define PWM_MAX_DTEST_LINES 4 -#define QPNP_HAP_EXT_PWM_DTEST_MASK 0x0F +#define QPNP_HAP_EXT_PWM_DTEST_MASK GENMASK(6, 4) #define QPNP_HAP_EXT_PWM_DTEST_SHFT 4 #define QPNP_HAP_EXT_PWM_PEAK_DATA 0x7F #define QPNP_HAP_EXT_PWM_HALF_DUTY 50 @@ -125,12 +138,10 @@ #define QPNP_HAP_WAV_SAMP_MAX 0x7E #define QPNP_HAP_BRAKE_PAT_LEN 4 #define QPNP_HAP_PLAY_EN 0x80 -#define QPNP_HAP_EN 0x80 -#define QPNP_HAP_BRAKE_MASK 0xFE -#define QPNP_HAP_TEST2_AUTO_RES_MASK 0x7F -#define QPNP_HAP_SEC_UNLOCK 0xA5 -#define AUTO_RES_ENABLE 0x80 -#define AUTO_RES_DISABLE 0x00 +#define QPNP_HAP_EN_BIT BIT(7) +#define QPNP_HAP_BRAKE_MASK BIT(0) +#define QPNP_HAP_AUTO_RES_MASK BIT(7) +#define AUTO_RES_ENABLE BIT(7) #define AUTO_RES_ERR_BIT 0x10 #define SC_FOUND_BIT 0x08 #define SC_MAX_DURATION 5 @@ -142,13 +153,7 @@ #define QPNP_TEST_TIMER_MS 5 #define QPNP_HAP_TIME_REQ_FOR_BACK_EMF_GEN 20000 - -#define MISC_TRIM_ERROR_RC19P2_CLK 0x09F5 -#define MISC_SEC_ACCESS 0x09D0 -#define MISC_SEC_UNLOCK 0xA5 -#define PMI8950_MISC_SID 2 - -#define POLL_TIME_AUTO_RES_ERR_NS (5 * NSEC_PER_MSEC) +#define POLL_TIME_AUTO_RES_ERR_NS (20 * NSEC_PER_MSEC) #define MAX_POSITIVE_VARIATION_LRA_FREQ 30 #define MAX_NEGATIVE_VARIATION_LRA_FREQ -30 @@ -159,11 +164,11 @@ ((MAX_POSITIVE_VARIATION_LRA_FREQ - MAX_NEGATIVE_VARIATION_LRA_FREQ) \ / FREQ_VARIATION_STEP) #define LRA_DRIVE_PERIOD_POS_ERR(hap, rc_clk_err_percent) \ - (hap->init_drive_period_code = (hap->init_drive_period_code * \ - (1000 + rc_clk_err_percent_x10)) / 1000) + (hap->init_drive_period_code = (hap->init_drive_period_code * \ + (1000 + rc_clk_err_percent_x10)) / 1000) #define LRA_DRIVE_PERIOD_NEG_ERR(hap, rc_clk_err_percent) \ - (hap->init_drive_period_code = (hap->init_drive_period_code * \ - (1000 - rc_clk_err_percent_x10)) / 1000) + (hap->init_drive_period_code = (hap->init_drive_period_code * \ + (1000 - rc_clk_err_percent_x10)) / 1000) u32 adjusted_lra_play_rate_code[ADJUSTED_LRA_PLAY_RATE_CODE_ARRSIZE]; @@ -222,9 +227,14 @@ enum qpnp_hap_auto_res_mode { QPNP_HAP_AUTO_RES_ZXD_EOP, }; +enum qpnp_hap_pm660_auto_res_mode { + QPNP_HAP_PM660_AUTO_RES_ZXD, + QPNP_HAP_PM660_AUTO_RES_QWD, +}; + /* high Z option lines */ enum qpnp_hap_high_z { - QPNP_HAP_LRA_HIGH_Z_NONE, + QPNP_HAP_LRA_HIGH_Z_NONE, /* opt0 for PM660 */ QPNP_HAP_LRA_HIGH_Z_OPT1, QPNP_HAP_LRA_HIGH_Z_OPT2, QPNP_HAP_LRA_HIGH_Z_OPT3, @@ -238,6 +248,11 @@ enum qpnp_hap_mode { QPNP_HAP_PWM, }; +/* status flags */ +enum qpnp_hap_status { + AUTO_RESONANCE_ENABLED = BIT(0), +}; + /* pwm channel info */ struct qpnp_pwm_info { struct pwm_device *pwm_dev; @@ -253,7 +268,6 @@ struct qpnp_pwm_info { * @ auto_res_err_poll_timer - hrtimer for auto-resonance error * @ timed_dev - timed output device * @ work - worker - * @ auto_res_err_work - correct auto resonance error * @ sc_work - worker to handle short circuit condition * @ pwm_info - pwm info * @ lock - mutex lock @@ -267,6 +281,7 @@ struct qpnp_pwm_info { percentage variation on the higher side. * @ drive_period_code_min_limit - calculated drive period code with percentage variation on the lower side + * @ lra_res_cal_period - LRA resonance calibration period * @ play_mode - play mode * @ auto_res_mode - auto resonace mode * @ lra_high_z - high z option line @@ -283,26 +298,26 @@ struct qpnp_pwm_info { * @ wave_s_rep_cnt - waveform sample repeat count * @ play_irq - irq for play * @ sc_irq - irq for short circuit + * @ status_flags - status * @ base - base address * @ act_type - actuator type * @ wave_shape - waveform shape * @ wave_samp - array of wave samples * @ shadow_wave_samp - shadow array of wave samples * @ brake_pat - pattern for active breaking - * @ reg_en_ctl - enable control register * @ reg_play - play register * @ lra_res_cal_period - period for resonance calibration * @ sc_duration - counter to determine the duration of short circuit condition + * @ lra_hw_auto_resonance - enable hardware auto resonance * @ state - current state of haptics - * @ use_play_irq - play irq usage state - * @ use_sc_irq - short circuit irq usage state * @ wf_update - waveform update flag * @ pwm_cfg_state - pwm mode configuration state * @ buffer_cfg_state - buffer mode configuration state * @ en_brake - brake state * @ sup_brake_pat - support custom brake pattern * @ correct_lra_drive_freq - correct LRA Drive Frequency - * @ misc_trim_error_rc19p2_clk_reg_present - if MISC Trim Error reg is present + * @ misc_clk_trim_error_reg - MISC clock trim error register if present + * @ clk_trim_error_code - MISC clock trim error code * @ perform_lra_auto_resonance_search - whether lra auto resonance search * algorithm should be performed or not. */ @@ -314,17 +329,19 @@ struct qpnp_hap { struct hrtimer auto_res_err_poll_timer; struct timed_output_dev timed_dev; struct work_struct work; - struct work_struct auto_res_err_work; struct delayed_work sc_work; struct hrtimer hap_test_timer; struct work_struct test_work; struct qpnp_pwm_info pwm_info; struct mutex lock; struct mutex wf_lock; + spinlock_t bus_lock; struct completion completion; enum qpnp_hap_mode play_mode; - enum qpnp_hap_auto_res_mode auto_res_mode; enum qpnp_hap_high_z lra_high_z; + int lra_qwd_drive_duration; + int calibrate_at_eop; + u32 misc_clk_trim_error_reg; u32 init_drive_period_code; u32 timeout_ms; u32 time_required_to_generate_back_emf_us; @@ -338,9 +355,12 @@ struct qpnp_hap { u32 wave_s_rep_cnt; u32 play_irq; u32 sc_irq; + u32 status_flags; u16 base; + u16 last_rate_cfg; u16 drive_period_code_max_limit; u16 drive_period_code_min_limit; + u16 lra_res_cal_period; u8 drive_period_code_max_limit_percent_variation; u8 drive_period_code_min_limit_percent_variation; u8 act_type; @@ -348,15 +368,15 @@ struct qpnp_hap { u8 wave_samp[QPNP_HAP_WAV_SAMP_LEN]; u8 shadow_wave_samp[QPNP_HAP_WAV_SAMP_LEN]; u8 brake_pat[QPNP_HAP_BRAKE_PAT_LEN]; - u8 reg_en_ctl; u8 reg_play; - u8 lra_res_cal_period; u8 sc_duration; u8 ext_pwm_dtest_line; + u8 pmic_subtype; + u8 auto_res_mode; + u8 clk_trim_error_code; + bool lra_hw_auto_resonance; bool vcc_pon_enabled; bool state; - bool use_play_irq; - bool use_sc_irq; bool manage_pon_supply; bool wf_update; bool pwm_cfg_state; @@ -364,88 +384,145 @@ struct qpnp_hap { bool en_brake; bool sup_brake_pat; bool correct_lra_drive_freq; - bool misc_trim_error_rc19p2_clk_reg_present; bool perform_lra_auto_resonance_search; }; static struct qpnp_hap *ghap; /* helper to read a pmic register */ -static int qpnp_hap_read_reg(struct qpnp_hap *hap, u8 *data, u16 addr) +static int qpnp_hap_read_mult_reg(struct qpnp_hap *hap, u16 addr, u8 *val, + int len) { int rc; - uint val; - rc = regmap_read(hap->regmap, addr, &val); + rc = regmap_bulk_read(hap->regmap, addr, val, len); if (rc < 0) - dev_err(&hap->pdev->dev, - "Error reading address: %X - ret %X\n", addr, rc); - *data = (u8)val; + pr_err("Error reading address: %X - ret %X\n", addr, rc); + + return rc; +} + +static int qpnp_hap_read_reg(struct qpnp_hap *hap, u16 addr, u8 *val) +{ + int rc; + uint tmp; + + rc = regmap_read(hap->regmap, addr, &tmp); + if (rc < 0) + pr_err("Error reading address: %X - ret %X\n", addr, rc); + else + *val = (u8)tmp; + return rc; } /* helper to write a pmic register */ -static int qpnp_hap_write_reg(struct qpnp_hap *hap, u8 *data, u16 addr) +static int qpnp_hap_write_mult_reg(struct qpnp_hap *hap, u16 addr, u8 *val, + int len) { + unsigned long flags; int rc; - rc = regmap_write(hap->regmap, addr, *data); + spin_lock_irqsave(&hap->bus_lock, flags); + rc = regmap_bulk_write(hap->regmap, addr, val, len); if (rc < 0) - dev_err(&hap->pdev->dev, - "Error writing address: %X - ret %X\n", addr, rc); + pr_err("Error writing address: %X - ret %X\n", addr, rc); - dev_dbg(&hap->pdev->dev, "write: HAP_0x%x = 0x%x\n", addr, *data); + spin_unlock_irqrestore(&hap->bus_lock, flags); + return rc; +} + +static int qpnp_hap_write_reg(struct qpnp_hap *hap, u16 addr, u8 val) +{ + unsigned long flags; + int rc; + + spin_lock_irqsave(&hap->bus_lock, flags); + rc = regmap_write(hap->regmap, addr, val); + if (rc < 0) + pr_err("Error writing address: %X - ret %X\n", addr, rc); + + spin_unlock_irqrestore(&hap->bus_lock, flags); + if (!rc) + pr_debug("wrote: HAP_0x%x = 0x%x\n", addr, val); return rc; } /* helper to access secure registers */ -static int qpnp_hap_sec_access(struct qpnp_hap *hap) +#define QPNP_HAP_SEC_UNLOCK 0xA5 +static int qpnp_hap_sec_masked_write_reg(struct qpnp_hap *hap, u16 addr, + u8 mask, u8 val) { + unsigned long flags; int rc; - u8 reg = QPNP_HAP_SEC_UNLOCK; + u8 tmp = QPNP_HAP_SEC_UNLOCK; - rc = qpnp_hap_write_reg(hap, ®, - QPNP_HAP_SEC_ACCESS_REG(hap->base)); - if (rc) - return rc; + spin_lock_irqsave(&hap->bus_lock, flags); + rc = regmap_write(hap->regmap, QPNP_HAP_SEC_ACCESS_REG(hap->base), tmp); + if (rc < 0) { + pr_err("Error writing sec_code - ret %X\n", rc); + goto out; + } - return 0; + rc = regmap_update_bits(hap->regmap, addr, mask, val); + if (rc < 0) + pr_err("Error writing address: %X - ret %X\n", addr, rc); + +out: + spin_unlock_irqrestore(&hap->bus_lock, flags); + if (!rc) + pr_debug("wrote: HAP_0x%x = 0x%x\n", addr, val); + return rc; +} + +static int qpnp_hap_masked_write_reg(struct qpnp_hap *hap, u16 addr, u8 mask, + u8 val) +{ + unsigned long flags; + int rc; + + spin_lock_irqsave(&hap->bus_lock, flags); + rc = regmap_update_bits(hap->regmap, addr, mask, val); + if (rc < 0) + pr_err("Error writing address: %X - ret %X\n", addr, rc); + + spin_unlock_irqrestore(&hap->bus_lock, flags); + if (!rc) + pr_debug("wrote: HAP_0x%x = 0x%x\n", addr, val); + return rc; } static void qpnp_handle_sc_irq(struct work_struct *work) { struct qpnp_hap *hap = container_of(work, struct qpnp_hap, sc_work.work); - u8 val, reg; + u8 val; - qpnp_hap_read_reg(hap, &val, QPNP_HAP_STATUS(hap->base)); + qpnp_hap_read_reg(hap, QPNP_HAP_STATUS(hap->base), &val); /* clear short circuit register */ if (val & SC_FOUND_BIT) { hap->sc_duration++; - reg = QPNP_HAP_SC_CLR; - qpnp_hap_write_reg(hap, ®, QPNP_HAP_SC_CLR_REG(hap->base)); + val = QPNP_HAP_SC_CLR; + qpnp_hap_write_reg(hap, QPNP_HAP_SC_CLR_REG(hap->base), val); } } -static int qpnp_hap_mod_enable(struct qpnp_hap *hap, int on) +static int qpnp_hap_mod_enable(struct qpnp_hap *hap, bool on) { u8 val; int rc, i; - val = hap->reg_en_ctl; - if (on) { - val |= QPNP_HAP_EN; - } else { + if (!on) { for (i = 0; i < QPNP_HAP_MAX_RETRIES; i++) { /* wait for 4 cycles of play rate */ unsigned long sleep_time = QPNP_HAP_CYCLS * hap->wave_play_rate_us; - rc = qpnp_hap_read_reg(hap, &val, - QPNP_HAP_STATUS(hap->base)); + rc = qpnp_hap_read_reg(hap, QPNP_HAP_STATUS(hap->base), + &val); - dev_dbg(&hap->pdev->dev, "HAP_STATUS=0x%x\n", val); + pr_debug("HAP_STATUS=0x%x\n", val); /* wait for QPNP_HAP_CYCLS cycles of play rate */ if (val & QPNP_HAP_STATUS_BUSY) { @@ -458,19 +535,14 @@ static int qpnp_hap_mod_enable(struct qpnp_hap *hap, int on) } if (i >= QPNP_HAP_MAX_RETRIES) - dev_dbg(&hap->pdev->dev, - "Haptics Busy. Force disable\n"); - - val &= ~QPNP_HAP_EN; + pr_debug("Haptics Busy. Force disable\n"); } - rc = qpnp_hap_write_reg(hap, &val, - QPNP_HAP_EN_CTL_REG(hap->base)); + val = on ? QPNP_HAP_EN_BIT : 0; + rc = qpnp_hap_write_reg(hap, QPNP_HAP_EN_CTL_REG(hap->base), val); if (rc < 0) return rc; - hap->reg_en_ctl = val; - return 0; } @@ -485,8 +557,7 @@ static int qpnp_hap_play(struct qpnp_hap *hap, int on) else val &= ~QPNP_HAP_PLAY_EN; - rc = qpnp_hap_write_reg(hap, &val, - QPNP_HAP_PLAY_REG(hap->base)); + rc = qpnp_hap_write_reg(hap, QPNP_HAP_PLAY_REG(hap->base), val); if (rc < 0) return rc; @@ -506,7 +577,7 @@ static ssize_t qpnp_hap_dump_regs_show(struct device *dev, u8 val; for (i = 0; i < ARRAY_SIZE(qpnp_hap_dbg_regs); i++) { - qpnp_hap_read_reg(hap, &val, hap->base + qpnp_hap_dbg_regs[i]); + qpnp_hap_read_reg(hap, hap->base + qpnp_hap_dbg_regs[i], &val); count += snprintf(buf + count, PAGE_SIZE - count, "qpnp_haptics: REG_0x%x = 0x%x\n", hap->base + qpnp_hap_dbg_regs[i], @@ -524,15 +595,15 @@ static irqreturn_t qpnp_hap_play_irq(int irq, void *_hap) { struct qpnp_hap *hap = _hap; int i, rc; - u8 reg; + u8 val; mutex_lock(&hap->wf_lock); /* Configure WAVE_SAMPLE1 to WAVE_SAMPLE8 register */ for (i = 0; i < QPNP_HAP_WAV_SAMP_LEN && hap->wf_update; i++) { - reg = hap->wave_samp[i] = hap->shadow_wave_samp[i]; - rc = qpnp_hap_write_reg(hap, ®, - QPNP_HAP_WAV_S_REG_BASE(hap->base) + i); + val = hap->wave_samp[i] = hap->shadow_wave_samp[i]; + rc = qpnp_hap_write_reg(hap, + QPNP_HAP_WAV_S_REG_BASE(hap->base) + i, val); if (rc) goto unlock; } @@ -549,13 +620,12 @@ static irqreturn_t qpnp_hap_sc_irq(int irq, void *_hap) { struct qpnp_hap *hap = _hap; int rc; - u8 disable_haptics = 0x00; u8 val; - dev_dbg(&hap->pdev->dev, "Short circuit detected\n"); + pr_debug("Short circuit detected\n"); if (hap->sc_duration < SC_MAX_DURATION) { - qpnp_hap_read_reg(hap, &val, QPNP_HAP_STATUS(hap->base)); + qpnp_hap_read_reg(hap, QPNP_HAP_STATUS(hap->base), &val); if (val & SC_FOUND_BIT) schedule_delayed_work(&hap->sc_work, QPNP_HAP_SC_IRQ_STATUS_DELAY); @@ -565,10 +635,10 @@ static irqreturn_t qpnp_hap_sc_irq(int irq, void *_hap) /* Disable haptics module if the duration of short circuit * exceeds the maximum limit (5 secs). */ - rc = qpnp_hap_write_reg(hap, &disable_haptics, - QPNP_HAP_EN_CTL_REG(hap->base)); - dev_err(&hap->pdev->dev, - "Haptics disabled permanently due to short circuit\n"); + val = 0; + rc = qpnp_hap_write_reg(hap, QPNP_HAP_EN_CTL_REG(hap->base), + val); + pr_err("Haptics disabled permanently due to short circuit\n"); } return IRQ_HANDLED; @@ -577,8 +647,8 @@ static irqreturn_t qpnp_hap_sc_irq(int irq, void *_hap) /* configuration api for buffer mode */ static int qpnp_hap_buffer_config(struct qpnp_hap *hap) { - u8 reg = 0; - int rc, i, temp; + u8 val = 0; + int rc, i; /* Configure the WAVE_REPEAT register */ if (hap->wave_rep_cnt < QPNP_HAP_WAV_REP_MIN) @@ -591,44 +661,22 @@ static int qpnp_hap_buffer_config(struct qpnp_hap *hap) else if (hap->wave_s_rep_cnt > QPNP_HAP_WAV_S_REP_MAX) hap->wave_s_rep_cnt = QPNP_HAP_WAV_S_REP_MAX; - rc = qpnp_hap_read_reg(hap, ®, - QPNP_HAP_WAV_REP_REG(hap->base)); - if (rc < 0) - return rc; - reg &= QPNP_HAP_WAV_REP_MASK; - temp = fls(hap->wave_rep_cnt) - 1; - reg |= (temp << QPNP_HAP_WAV_REP_SHFT); - reg &= QPNP_HAP_WAV_S_REP_MASK; - temp = fls(hap->wave_s_rep_cnt) - 1; - reg |= temp; - rc = qpnp_hap_write_reg(hap, ®, - QPNP_HAP_WAV_REP_REG(hap->base)); + val = ilog2(hap->wave_rep_cnt) << QPNP_HAP_WAV_REP_SHIFT | + ilog2(hap->wave_s_rep_cnt); + rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_WAV_REP_REG(hap->base), + QPNP_HAP_WAV_REP_MASK | QPNP_HAP_WAV_S_REP_MASK, val); if (rc) return rc; /* Configure WAVE_SAMPLE1 to WAVE_SAMPLE8 register */ - for (i = 0, reg = 0; i < QPNP_HAP_WAV_SAMP_LEN; i++) { - reg = hap->wave_samp[i]; - rc = qpnp_hap_write_reg(hap, ®, - QPNP_HAP_WAV_S_REG_BASE(hap->base) + i); + for (i = 0, val = 0; i < QPNP_HAP_WAV_SAMP_LEN; i++) { + val = hap->wave_samp[i]; + rc = qpnp_hap_write_reg(hap, + QPNP_HAP_WAV_S_REG_BASE(hap->base) + i, val); if (rc) return rc; } - /* setup play irq */ - if (hap->use_play_irq) { - rc = devm_request_threaded_irq(&hap->pdev->dev, hap->play_irq, - NULL, qpnp_hap_play_irq, - QPNP_IRQ_FLAGS, - "qpnp_play_irq", hap); - if (rc < 0) { - dev_err(&hap->pdev->dev, - "Unable to request play(%d) IRQ(err:%d)\n", - hap->play_irq, rc); - return rc; - } - } - hap->buffer_cfg_state = true; return 0; } @@ -636,59 +684,41 @@ static int qpnp_hap_buffer_config(struct qpnp_hap *hap) /* configuration api for pwm */ static int qpnp_hap_pwm_config(struct qpnp_hap *hap) { - u8 reg = 0; - int rc, temp; + u8 val = 0; + int rc; /* Configure the EXTERNAL_PWM register */ if (hap->ext_pwm_freq_khz <= QPNP_HAP_EXT_PWM_FREQ_25_KHZ) { hap->ext_pwm_freq_khz = QPNP_HAP_EXT_PWM_FREQ_25_KHZ; - temp = 0; + val = 0; } else if (hap->ext_pwm_freq_khz <= QPNP_HAP_EXT_PWM_FREQ_50_KHZ) { hap->ext_pwm_freq_khz = QPNP_HAP_EXT_PWM_FREQ_50_KHZ; - temp = 1; + val = 1; } else if (hap->ext_pwm_freq_khz <= QPNP_HAP_EXT_PWM_FREQ_75_KHZ) { hap->ext_pwm_freq_khz = QPNP_HAP_EXT_PWM_FREQ_75_KHZ; - temp = 2; + val = 2; } else { hap->ext_pwm_freq_khz = QPNP_HAP_EXT_PWM_FREQ_100_KHZ; - temp = 3; + val = 3; } - rc = qpnp_hap_read_reg(hap, ®, - QPNP_HAP_EXT_PWM_REG(hap->base)); - if (rc < 0) - return rc; - reg &= QPNP_HAP_EXT_PWM_MASK; - reg |= temp; - rc = qpnp_hap_write_reg(hap, ®, - QPNP_HAP_EXT_PWM_REG(hap->base)); + rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_EXT_PWM_REG(hap->base), + QPNP_HAP_EXT_PWM_MASK, val); if (rc) return rc; - rc = qpnp_hap_read_reg(hap, ®, - QPNP_HAP_TEST2_REG(hap->base)); - if (rc) - return rc; if (!hap->ext_pwm_dtest_line || hap->ext_pwm_dtest_line > PWM_MAX_DTEST_LINES) { - dev_err(&hap->pdev->dev, "invalid dtest line\n"); + pr_err("invalid dtest line\n"); return -EINVAL; } /* disable auto res for PWM mode */ - reg &= QPNP_HAP_EXT_PWM_DTEST_MASK; - temp = hap->ext_pwm_dtest_line << QPNP_HAP_EXT_PWM_DTEST_SHFT; - reg |= temp; - - /* TEST2 is a secure access register */ - rc = qpnp_hap_sec_access(hap); - if (rc) - return rc; - - rc = qpnp_hap_write_reg(hap, ®, - QPNP_HAP_TEST2_REG(hap->base)); + val = hap->ext_pwm_dtest_line << QPNP_HAP_EXT_PWM_DTEST_SHFT; + rc = qpnp_hap_sec_masked_write_reg(hap, QPNP_HAP_TEST2_REG(hap->base), + QPNP_HAP_EXT_PWM_DTEST_MASK | QPNP_HAP_AUTO_RES_MASK, val); if (rc) return rc; @@ -696,7 +726,7 @@ static int qpnp_hap_pwm_config(struct qpnp_hap *hap) hap->pwm_info.duty_us * NSEC_PER_USEC, hap->pwm_info.period_us * NSEC_PER_USEC); if (rc < 0) { - dev_err(&hap->pdev->dev, "hap pwm config failed\n"); + pr_err("hap pwm config failed\n"); pwm_free(hap->pwm_info.pwm_dev); return -ENODEV; } @@ -706,72 +736,180 @@ static int qpnp_hap_pwm_config(struct qpnp_hap *hap) return 0; } +static int qpnp_hap_lra_auto_res_config(struct qpnp_hap *hap) +{ + int rc; + u8 val, mask; + + /* disable auto resonance for ERM */ + if (hap->act_type == QPNP_HAP_ERM) { + val = 0x00; + rc = qpnp_hap_write_reg(hap, + QPNP_HAP_LRA_AUTO_RES_REG(hap->base), val); + return rc; + } + + if (hap->lra_hw_auto_resonance) { + rc = qpnp_hap_masked_write_reg(hap, + QPNP_HAP_PM660_HW_AUTO_RES_MODE_BIT, + QPNP_HAP_AUTO_RES_CTRL(hap->base), + QPNP_HAP_PM660_HW_AUTO_RES_MODE_BIT); + if (rc) + return rc; + } + + if (hap->lra_res_cal_period < QPNP_HAP_RES_CAL_PERIOD_MIN) + hap->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MIN; + + if (hap->pmic_subtype == PM660_SUBTYPE) { + if (hap->lra_res_cal_period > + QPNP_HAP_PM660_RES_CAL_PERIOD_MAX) + hap->lra_res_cal_period = + QPNP_HAP_PM660_RES_CAL_PERIOD_MAX; + + if (hap->auto_res_mode == QPNP_HAP_PM660_AUTO_RES_QWD) + hap->lra_res_cal_period = 0; + } else { + if (hap->lra_res_cal_period > QPNP_HAP_RES_CAL_PERIOD_MAX) + hap->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MAX; + } + + val = mask = 0; + if (hap->lra_res_cal_period) + val = ilog2(hap->lra_res_cal_period / + QPNP_HAP_RES_CAL_PERIOD_MIN); + + if (hap->pmic_subtype == PM660_SUBTYPE) { + val |= hap->auto_res_mode << + QPNP_HAP_PM660_AUTO_RES_MODE_SHIFT; + mask = QPNP_HAP_PM660_AUTO_RES_MODE_BIT; + val |= hap->lra_high_z << + QPNP_HAP_PM660_CALIBRATE_DURATION_SHIFT; + mask |= QPNP_HAP_PM660_CALIBRATE_DURATION_MASK; + if (hap->lra_qwd_drive_duration != -EINVAL) { + val |= hap->lra_qwd_drive_duration << + QPNP_HAP_PM660_QWD_DRIVE_DURATION_SHIFT; + mask |= QPNP_HAP_PM660_QWD_DRIVE_DURATION_BIT; + } + if (hap->calibrate_at_eop != -EINVAL) { + val |= hap->calibrate_at_eop << + QPNP_HAP_PM660_CALIBRATE_AT_EOP_SHIFT; + mask |= QPNP_HAP_PM660_CALIBRATE_AT_EOP_BIT; + } + mask |= QPNP_HAP_PM660_LRA_RES_CAL_PER_MASK; + } else { + val |= (hap->auto_res_mode << QPNP_HAP_AUTO_RES_MODE_SHIFT); + val |= (hap->lra_high_z << QPNP_HAP_LRA_HIGH_Z_SHIFT); + mask = QPNP_HAP_AUTO_RES_MODE_MASK | QPNP_HAP_LRA_HIGH_Z_MASK | + QPNP_HAP_LRA_RES_CAL_PER_MASK; + } + + rc = qpnp_hap_masked_write_reg(hap, + QPNP_HAP_LRA_AUTO_RES_REG(hap->base), mask, val); + return rc; +} + /* configuration api for play mode */ static int qpnp_hap_play_mode_config(struct qpnp_hap *hap) { - u8 reg = 0; - int rc, temp; + u8 val = 0; + int rc; - rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_PLAY_MODE_REG(hap->base)); - if (rc < 0) - return rc; - reg &= QPNP_HAP_PLAY_MODE_MASK; - temp = hap->play_mode << QPNP_HAP_PLAY_MODE_SHFT; - reg |= temp; - rc = qpnp_hap_write_reg(hap, ®, QPNP_HAP_PLAY_MODE_REG(hap->base)); - if (rc) - return rc; - return 0; + val = hap->play_mode << QPNP_HAP_WF_SOURCE_SHIFT; + rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_SEL_REG(hap->base), + QPNP_HAP_WF_SOURCE_MASK, val); + return rc; } -/* configuration api for max volatge */ +/* configuration api for max voltage */ static int qpnp_hap_vmax_config(struct qpnp_hap *hap) { - u8 reg = 0; - int rc, temp; + u8 val = 0; + int rc; if (hap->vmax_mv < QPNP_HAP_VMAX_MIN_MV) hap->vmax_mv = QPNP_HAP_VMAX_MIN_MV; else if (hap->vmax_mv > QPNP_HAP_VMAX_MAX_MV) hap->vmax_mv = QPNP_HAP_VMAX_MAX_MV; - rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_VMAX_REG(hap->base)); - if (rc < 0) - return rc; - reg &= QPNP_HAP_VMAX_MASK; - temp = hap->vmax_mv / QPNP_HAP_VMAX_MIN_MV; - reg |= (temp << QPNP_HAP_VMAX_SHIFT); - rc = qpnp_hap_write_reg(hap, ®, QPNP_HAP_VMAX_REG(hap->base)); - if (rc) - return rc; + val = (hap->vmax_mv / QPNP_HAP_VMAX_MIN_MV) << QPNP_HAP_VMAX_SHIFT; + rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_VMAX_REG(hap->base), + QPNP_HAP_VMAX_MASK, val); + return rc; +} - return 0; +/* configuration api for ilim */ +static int qpnp_hap_ilim_config(struct qpnp_hap *hap) +{ + u8 val = 0; + int rc; + + if (hap->ilim_ma < QPNP_HAP_ILIM_MIN_MA) + hap->ilim_ma = QPNP_HAP_ILIM_MIN_MA; + else if (hap->ilim_ma > QPNP_HAP_ILIM_MAX_MA) + hap->ilim_ma = QPNP_HAP_ILIM_MAX_MA; + + val = (hap->ilim_ma / QPNP_HAP_ILIM_MIN_MA) - 1; + rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_ILIM_REG(hap->base), + QPNP_HAP_ILIM_MASK, val); + return rc; } /* configuration api for short circuit debounce */ static int qpnp_hap_sc_deb_config(struct qpnp_hap *hap) { - u8 reg = 0; - int rc, temp; + u8 val = 0; + int rc; if (hap->sc_deb_cycles < QPNP_HAP_SC_DEB_CYCLES_MIN) hap->sc_deb_cycles = QPNP_HAP_SC_DEB_CYCLES_MIN; else if (hap->sc_deb_cycles > QPNP_HAP_SC_DEB_CYCLES_MAX) hap->sc_deb_cycles = QPNP_HAP_SC_DEB_CYCLES_MAX; - rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_SC_DEB_REG(hap->base)); - if (rc < 0) - return rc; - reg &= QPNP_HAP_SC_DEB_MASK; - if (hap->sc_deb_cycles) { - temp = fls(hap->sc_deb_cycles) - 1; - reg |= temp - QPNP_HAP_SC_DEB_SUB; + if (hap->sc_deb_cycles != QPNP_HAP_SC_DEB_CYCLES_MIN) + val = ilog2(hap->sc_deb_cycles / + QPNP_HAP_DEF_SC_DEB_CYCLES) + 1; + else + val = QPNP_HAP_SC_DEB_CYCLES_MIN; + + rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_SC_DEB_REG(hap->base), + QPNP_HAP_SC_DEB_MASK, val); + + return rc; +} + +static int qpnp_hap_int_pwm_config(struct qpnp_hap *hap) +{ + int rc; + u8 val; + + if (hap->int_pwm_freq_khz <= QPNP_HAP_INT_PWM_FREQ_253_KHZ) { + if (hap->pmic_subtype == PM660_SUBTYPE) { + hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_505_KHZ; + val = 1; + } else { + hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_253_KHZ; + val = 0; + } + } else if (hap->int_pwm_freq_khz <= QPNP_HAP_INT_PWM_FREQ_505_KHZ) { + hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_505_KHZ; + val = 1; + } else if (hap->int_pwm_freq_khz <= QPNP_HAP_INT_PWM_FREQ_739_KHZ) { + hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_739_KHZ; + val = 2; + } else { + hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_1076_KHZ; + val = 3; } - rc = qpnp_hap_write_reg(hap, ®, QPNP_HAP_SC_DEB_REG(hap->base)); + + rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_INT_PWM_REG(hap->base), + QPNP_HAP_INT_PWM_MASK, val); if (rc) return rc; - return 0; + rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_PWM_CAP_REG(hap->base), + QPNP_HAP_INT_PWM_MASK, val); + return rc; } /* DT parsing api for buffer mode */ @@ -788,7 +926,7 @@ static int qpnp_hap_parse_buffer_dt(struct qpnp_hap *hap) if (!rc) { hap->wave_rep_cnt = temp; } else if (rc != -EINVAL) { - dev_err(&pdev->dev, "Unable to read rep cnt\n"); + pr_err("Unable to read rep cnt\n"); return rc; } @@ -798,30 +936,20 @@ static int qpnp_hap_parse_buffer_dt(struct qpnp_hap *hap) if (!rc) { hap->wave_s_rep_cnt = temp; } else if (rc != -EINVAL) { - dev_err(&pdev->dev, "Unable to read samp rep cnt\n"); + pr_err("Unable to read samp rep cnt\n"); return rc; } prop = of_find_property(pdev->dev.of_node, "qcom,wave-samples", &temp); if (!prop || temp != QPNP_HAP_WAV_SAMP_LEN) { - dev_err(&pdev->dev, "Invalid wave samples, use default"); + pr_err("Invalid wave samples, use default"); for (i = 0; i < QPNP_HAP_WAV_SAMP_LEN; i++) hap->wave_samp[i] = QPNP_HAP_WAV_SAMP_MAX; } else { memcpy(hap->wave_samp, prop->value, QPNP_HAP_WAV_SAMP_LEN); } - hap->use_play_irq = of_property_read_bool(pdev->dev.of_node, - "qcom,use-play-irq"); - if (hap->use_play_irq) { - hap->play_irq = platform_get_irq_byname(hap->pdev, "play-irq"); - if (hap->play_irq < 0) { - dev_err(&pdev->dev, "Unable to get play irq\n"); - return hap->play_irq; - } - } - return 0; } @@ -838,7 +966,7 @@ static int qpnp_hap_parse_pwm_dt(struct qpnp_hap *hap) if (!rc) { hap->ext_pwm_freq_khz = temp; } else if (rc != -EINVAL) { - dev_err(&pdev->dev, "Unable to read ext pwm freq\n"); + pr_err("Unable to read ext pwm freq\n"); return rc; } @@ -853,7 +981,7 @@ static int qpnp_hap_parse_pwm_dt(struct qpnp_hap *hap) if (IS_ERR(hap->pwm_info.pwm_dev)) { rc = PTR_ERR(hap->pwm_info.pwm_dev); - dev_err(&pdev->dev, "Cannot get PWM device rc:(%d)\n", rc); + pr_err("Cannot get PWM device rc:(%d)\n", rc); hap->pwm_info.pwm_dev = NULL; return rc; } @@ -888,7 +1016,7 @@ static ssize_t qpnp_hap_wf_samp_show(struct device *dev, char *buf, int index) timed_dev); if (index < 0 || index >= QPNP_HAP_WAV_SAMP_LEN) { - dev_err(dev, "Invalid sample index(%d)\n", index); + pr_err("Invalid sample index(%d)\n", index); return -EINVAL; } @@ -954,7 +1082,7 @@ static ssize_t qpnp_hap_wf_samp_store(struct device *dev, int data, rc; if (index < 0 || index >= QPNP_HAP_WAV_SAMP_LEN) { - dev_err(dev, "Invalid sample index(%d)\n", index); + pr_err("Invalid sample index(%d)\n", index); return -EINVAL; } @@ -963,7 +1091,7 @@ static ssize_t qpnp_hap_wf_samp_store(struct device *dev, return rc; if (data < 0 || data > 0xff) { - dev_err(dev, "Invalid sample wf_%d (%d)\n", index, data); + pr_err("Invalid sample wf_%d (%d)\n", index, data); return -EINVAL; } @@ -1063,8 +1191,8 @@ static ssize_t qpnp_hap_wf_rep_store(struct device *dev, struct timed_output_dev *timed_dev = dev_get_drvdata(dev); struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, timed_dev); - int data, rc, temp; - u8 reg; + int data, rc; + u8 val; rc = kstrtoint(buf, 10, &data); if (rc) @@ -1075,19 +1203,11 @@ static ssize_t qpnp_hap_wf_rep_store(struct device *dev, else if (data > QPNP_HAP_WAV_REP_MAX) data = QPNP_HAP_WAV_REP_MAX; - rc = qpnp_hap_read_reg(hap, ®, - QPNP_HAP_WAV_REP_REG(hap->base)); - if (rc < 0) - return rc; - reg &= QPNP_HAP_WAV_REP_MASK; - temp = fls(data) - 1; - reg |= (temp << QPNP_HAP_WAV_REP_SHFT); - rc = qpnp_hap_write_reg(hap, ®, - QPNP_HAP_WAV_REP_REG(hap->base)); - if (rc) - return rc; - - hap->wave_rep_cnt = data; + val = ilog2(data) << QPNP_HAP_WAV_REP_SHIFT; + rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_WAV_REP_REG(hap->base), + QPNP_HAP_WAV_REP_MASK, val); + if (!rc) + hap->wave_rep_cnt = data; return count; } @@ -1110,8 +1230,8 @@ static ssize_t qpnp_hap_wf_s_rep_store(struct device *dev, struct timed_output_dev *timed_dev = dev_get_drvdata(dev); struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, timed_dev); - int data, rc, temp; - u8 reg; + int data, rc; + u8 val; rc = kstrtoint(buf, 10, &data); if (rc) @@ -1122,19 +1242,11 @@ static ssize_t qpnp_hap_wf_s_rep_store(struct device *dev, else if (data > QPNP_HAP_WAV_S_REP_MAX) data = QPNP_HAP_WAV_S_REP_MAX; - rc = qpnp_hap_read_reg(hap, ®, - QPNP_HAP_WAV_REP_REG(hap->base)); - if (rc < 0) - return rc; - reg &= QPNP_HAP_WAV_S_REP_MASK; - temp = fls(data) - 1; - reg |= temp; - rc = qpnp_hap_write_reg(hap, ®, - QPNP_HAP_WAV_REP_REG(hap->base)); - if (rc) - return rc; - - hap->wave_s_rep_cnt = data; + val = ilog2(hap->wave_s_rep_cnt); + rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_WAV_REP_REG(hap->base), + QPNP_HAP_WAV_S_REP_MASK, val); + if (!rc) + hap->wave_s_rep_cnt = data; return count; } @@ -1355,25 +1467,22 @@ static int calculate_lra_code(struct qpnp_hap *hap) u8 neg_idx = 0, pos_idx = ADJUSTED_LRA_PLAY_RATE_CODE_ARRSIZE - 1; int rc = 0; - rc = qpnp_hap_read_reg(hap, &lra_drive_period_code_lo, - QPNP_HAP_RATE_CFG1_REG(hap->base)); + rc = qpnp_hap_read_reg(hap, QPNP_HAP_RATE_CFG1_REG(hap->base), + &lra_drive_period_code_lo); if (rc) { - dev_err(&hap->pdev->dev, - "Error while reading RATE_CFG1 register\n"); + pr_err("Error while reading RATE_CFG1 register\n"); return rc; } - rc = qpnp_hap_read_reg(hap, &lra_drive_period_code_hi, - QPNP_HAP_RATE_CFG2_REG(hap->base)); + rc = qpnp_hap_read_reg(hap, QPNP_HAP_RATE_CFG2_REG(hap->base), + &lra_drive_period_code_hi); if (rc) { - dev_err(&hap->pdev->dev, - "Error while reading RATE_CFG2 register\n"); + pr_err("Error while reading RATE_CFG2 register\n"); return rc; } if (!lra_drive_period_code_lo && !lra_drive_period_code_hi) { - dev_err(&hap->pdev->dev, - "Unexpected Error: both RATE_CFG1 and RATE_CFG2 read 0\n"); + pr_err("Unexpected Error: both RATE_CFG1 and RATE_CFG2 read 0\n"); return -EINVAL; } @@ -1391,16 +1500,14 @@ static int calculate_lra_code(struct qpnp_hap *hap) start_variation -= AUTO_RES_ERROR_CAPTURE_RES; } - dev_dbg(&hap->pdev->dev, - "lra_drive_period_code_lo = 0x%x lra_drive_period_code_hi = 0x%x\n" + pr_debug("lra_drive_period_code_lo = 0x%x lra_drive_period_code_hi = 0x%x\n" "lra_drive_period_code = 0x%x, lra_drive_frequency_hz = 0x%x\n" "Calculated play rate code values are :\n", lra_drive_period_code_lo, lra_drive_period_code_hi, lra_drive_period_code, lra_drive_frequency_hz); for (i = 0; i < ADJUSTED_LRA_PLAY_RATE_CODE_ARRSIZE; ++i) - dev_dbg(&hap->pdev->dev, - " 0x%x", adjusted_lra_play_rate_code[i]); + pr_debug(" 0x%x", adjusted_lra_play_rate_code[i]); return 0; } @@ -1410,77 +1517,98 @@ static int qpnp_hap_auto_res_enable(struct qpnp_hap *hap, int enable) int rc = 0; u8 val; - rc = qpnp_hap_read_reg(hap, &val, QPNP_HAP_TEST2_REG(hap->base)); + val = enable ? AUTO_RES_ENABLE : 0; + if (hap->pmic_subtype == PM660_SUBTYPE) + rc = qpnp_hap_masked_write_reg(hap, + QPNP_HAP_AUTO_RES_CTRL(hap->base), + QPNP_HAP_AUTO_RES_MASK, val); + else + rc = qpnp_hap_sec_masked_write_reg(hap, + QPNP_HAP_TEST2_REG(hap->base), + QPNP_HAP_AUTO_RES_MASK, val); if (rc < 0) return rc; - val &= QPNP_HAP_TEST2_AUTO_RES_MASK; if (enable) - val |= AUTO_RES_ENABLE; + hap->status_flags |= AUTO_RESONANCE_ENABLED; else - val |= AUTO_RES_DISABLE; + hap->status_flags &= ~AUTO_RESONANCE_ENABLED; - /* TEST2 is a secure access register */ - rc = qpnp_hap_sec_access(hap); - if (rc) - return rc; - - rc = qpnp_hap_write_reg(hap, &val, QPNP_HAP_TEST2_REG(hap->base)); - if (rc) - return rc; - - return 0; + return rc; } static void update_lra_frequency(struct qpnp_hap *hap) { - u8 lra_auto_res_lo = 0, lra_auto_res_hi = 0; + u8 lra_auto_res[2], val; u32 play_rate_code; + u16 rate_cfg; + int rc; - qpnp_hap_read_reg(hap, &lra_auto_res_lo, - QPNP_HAP_LRA_AUTO_RES_LO(hap->base)); - qpnp_hap_read_reg(hap, &lra_auto_res_hi, - QPNP_HAP_LRA_AUTO_RES_HI(hap->base)); + rc = qpnp_hap_read_mult_reg(hap, QPNP_HAP_LRA_AUTO_RES_LO(hap->base), + lra_auto_res, 2); + if (rc < 0) { + pr_err("Error in reading LRA_AUTO_RES_LO/HI, rc=%d\n", rc); + return; + } play_rate_code = - (lra_auto_res_hi & 0xF0) << 4 | (lra_auto_res_lo & 0xFF); + (lra_auto_res[1] & 0xF0) << 4 | (lra_auto_res[0] & 0xFF); - dev_dbg(&hap->pdev->dev, - "lra_auto_res_lo = 0x%x lra_auto_res_hi = 0x%x play_rate_code = 0x%x\n", - lra_auto_res_lo, lra_auto_res_hi, play_rate_code); + pr_debug("lra_auto_res_lo = 0x%x lra_auto_res_hi = 0x%x play_rate_code = 0x%x\n", + lra_auto_res[0], lra_auto_res[1], play_rate_code); + + rc = qpnp_hap_read_reg(hap, QPNP_HAP_STATUS(hap->base), &val); + if (rc < 0) + return; /* - * If the drive period code read from AUTO RES_LO and AUTO_RES_HI - * registers is more than the max limit percent variation read from - * DT or less than the min limit percent variation read from DT, then - * RATE_CFG registers are not uptdated. + * If the drive period code read from AUTO_RES_LO and AUTO_RES_HI + * registers is more than the max limit percent variation or less + * than the min limit percent variation specified through DT, then + * auto-resonance is disabled. */ - if ((play_rate_code <= hap->drive_period_code_min_limit) || - (play_rate_code >= hap->drive_period_code_max_limit)) + if ((val & AUTO_RES_ERR_BIT) || + ((play_rate_code <= hap->drive_period_code_min_limit) || + (play_rate_code >= hap->drive_period_code_max_limit))) { + if (val & AUTO_RES_ERR_BIT) + pr_debug("Auto-resonance error %x\n", val); + else + pr_debug("play rate %x out of bounds [min: 0x%x, max: 0x%x]\n", + play_rate_code, + hap->drive_period_code_min_limit, + hap->drive_period_code_max_limit); + rc = qpnp_hap_auto_res_enable(hap, 0); + if (rc < 0) + pr_debug("Auto-resonance write failed\n"); return; + } - qpnp_hap_write_reg(hap, &lra_auto_res_lo, - QPNP_HAP_RATE_CFG1_REG(hap->base)); + lra_auto_res[1] >>= 4; + rate_cfg = lra_auto_res[1] << 8 | lra_auto_res[0]; + if (hap->last_rate_cfg == rate_cfg) { + pr_debug("Same rate_cfg, skip updating\n"); + return; + } - lra_auto_res_hi = lra_auto_res_hi >> 4; - qpnp_hap_write_reg(hap, &lra_auto_res_hi, - QPNP_HAP_RATE_CFG2_REG(hap->base)); + rc = qpnp_hap_write_mult_reg(hap, QPNP_HAP_RATE_CFG1_REG(hap->base), + lra_auto_res, 2); + if (rc < 0) { + pr_err("Error in writing to RATE_CFG1/2, rc=%d\n", rc); + } else { + pr_debug("Update RATE_CFG with [0x%x]\n", rate_cfg); + hap->last_rate_cfg = rate_cfg; + } } static enum hrtimer_restart detect_auto_res_error(struct hrtimer *timer) { struct qpnp_hap *hap = container_of(timer, struct qpnp_hap, auto_res_err_poll_timer); - u8 val; ktime_t currtime; - qpnp_hap_read_reg(hap, &val, QPNP_HAP_STATUS(hap->base)); - - if (val & AUTO_RES_ERR_BIT) { - schedule_work(&hap->auto_res_err_work); + if (!(hap->status_flags & AUTO_RESONANCE_ENABLED)) return HRTIMER_NORESTART; - } update_lra_frequency(hap); currtime = ktime_get(); @@ -1489,56 +1617,11 @@ static enum hrtimer_restart detect_auto_res_error(struct hrtimer *timer) return HRTIMER_RESTART; } -static void correct_auto_res_error(struct work_struct *auto_res_err_work) -{ - struct qpnp_hap *hap = container_of(auto_res_err_work, - struct qpnp_hap, auto_res_err_work); - - u8 lra_code_lo, lra_code_hi, disable_hap = 0x00; - static u8 lra_freq_index; - ktime_t currtime = ktime_set(0, 0), remaining_time = ktime_set(0, 0); - - if (hrtimer_active(&hap->hap_timer)) - remaining_time = hrtimer_get_remaining(&hap->hap_timer); - - qpnp_hap_play(hap, 0); - qpnp_hap_write_reg(hap, &disable_hap, - QPNP_HAP_EN_CTL_REG(hap->base)); - - if (hap->perform_lra_auto_resonance_search) { - lra_code_lo = - adjusted_lra_play_rate_code[lra_freq_index] - & QPNP_HAP_RATE_CFG1_MASK; - - qpnp_hap_write_reg(hap, &lra_code_lo, - QPNP_HAP_RATE_CFG1_REG(hap->base)); - - lra_code_hi = adjusted_lra_play_rate_code[lra_freq_index] - >> QPNP_HAP_RATE_CFG2_SHFT; - - qpnp_hap_write_reg(hap, &lra_code_hi, - QPNP_HAP_RATE_CFG2_REG(hap->base)); - - lra_freq_index = (lra_freq_index+1) % - ADJUSTED_LRA_PLAY_RATE_CODE_ARRSIZE; - } - - dev_dbg(&hap->pdev->dev, "Remaining time is %lld\n", - ktime_to_us(remaining_time)); - - if ((ktime_to_us(remaining_time)) > 0) { - currtime = ktime_get(); - hap->state = 1; - hrtimer_forward(&hap->hap_timer, currtime, remaining_time); - schedule_work(&hap->work); - } -} - /* set api for haptics */ static int qpnp_hap_set(struct qpnp_hap *hap, int on) { + u8 auto_res_mode_qwd; int rc = 0; - u8 val = 0; unsigned long timeout_ns = POLL_TIME_AUTO_RES_ERR_NS; u32 back_emf_delay_us = hap->time_required_to_generate_back_emf_us; @@ -1562,9 +1645,16 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on) * and enable it after the sleep of * 'time_required_to_generate_back_emf_us' is completed. */ + if (hap->pmic_subtype == PM660_SUBTYPE) + auto_res_mode_qwd = (hap->auto_res_mode == + QPNP_HAP_PM660_AUTO_RES_QWD); + else + auto_res_mode_qwd = (hap->auto_res_mode == + QPNP_HAP_AUTO_RES_QWD); + if ((hap->act_type == QPNP_HAP_LRA) && (hap->correct_lra_drive_freq || - hap->auto_res_mode == QPNP_HAP_AUTO_RES_QWD)) + auto_res_mode_qwd)) qpnp_hap_auto_res_enable(hap, 0); rc = qpnp_hap_mod_enable(hap, on); @@ -1575,7 +1665,7 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on) if ((hap->act_type == QPNP_HAP_LRA) && (hap->correct_lra_drive_freq || - hap->auto_res_mode == QPNP_HAP_AUTO_RES_QWD)) { + auto_res_mode_qwd)) { usleep_range(back_emf_delay_us, (back_emf_delay_us + 1)); @@ -1584,7 +1674,8 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on) return rc; } if (hap->act_type == QPNP_HAP_LRA && - hap->correct_lra_drive_freq) { + hap->correct_lra_drive_freq && + !hap->lra_hw_auto_resonance) { /* * Start timer to poll Auto Resonance error bit */ @@ -1601,16 +1692,16 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on) return rc; if (hap->act_type == QPNP_HAP_LRA && - hap->correct_lra_drive_freq) { - rc = qpnp_hap_read_reg(hap, &val, - QPNP_HAP_STATUS(hap->base)); - if (!(val & AUTO_RES_ERR_BIT)) - update_lra_frequency(hap); + hap->correct_lra_drive_freq && + (hap->status_flags & AUTO_RESONANCE_ENABLED) && + !hap->lra_hw_auto_resonance) { + update_lra_frequency(hap); } rc = qpnp_hap_mod_enable(hap, on); if (hap->act_type == QPNP_HAP_LRA && - hap->correct_lra_drive_freq) { + hap->correct_lra_drive_freq && + !hap->lra_hw_auto_resonance) { hrtimer_cancel(&hap->auto_res_err_poll_timer); } } @@ -1628,7 +1719,8 @@ static void qpnp_hap_td_enable(struct timed_output_dev *dev, int value) mutex_lock(&hap->lock); if (hap->act_type == QPNP_HAP_LRA && - hap->correct_lra_drive_freq) + hap->correct_lra_drive_freq && + !hap->lra_hw_auto_resonance) hrtimer_cancel(&hap->auto_res_err_poll_timer); hrtimer_cancel(&hap->hap_timer); @@ -1663,7 +1755,7 @@ int qpnp_hap_play_byte(u8 data, bool on) } if (hap->play_mode != QPNP_HAP_PWM) { - dev_err(&hap->pdev->dev, "only PWM mode is supported\n"); + pr_err("only PWM mode is supported\n"); return -EINVAL; } @@ -1704,8 +1796,7 @@ int qpnp_hap_play_byte(u8 data, bool on) if (rc) return rc; - dev_dbg(&hap->pdev->dev, "data=0x%x duty_per=%d\n", data, - duty_percent); + pr_debug("data=0x%x duty_per=%d\n", data, duty_percent); rc = qpnp_hap_set(hap, true); @@ -1724,8 +1815,8 @@ static void qpnp_hap_worker(struct work_struct *work) if (hap->vcc_pon && hap->state && !hap->vcc_pon_enabled) { rc = regulator_enable(hap->vcc_pon); if (rc < 0) - pr_err("%s: could not enable vcc_pon regulator rc=%d\n", - __func__, rc); + pr_err("could not enable vcc_pon regulator rc=%d\n", + rc); else hap->vcc_pon_enabled = true; } @@ -1734,8 +1825,8 @@ static void qpnp_hap_worker(struct work_struct *work) * exceeds the maximum limit (5 secs). */ if (hap->sc_duration == SC_MAX_DURATION) { - rc = qpnp_hap_write_reg(hap, &val, - QPNP_HAP_EN_CTL_REG(hap->base)); + rc = qpnp_hap_write_reg(hap, QPNP_HAP_EN_CTL_REG(hap->base), + val); } else { if (hap->play_mode == QPNP_HAP_PWM) qpnp_hap_mod_enable(hap, hap->state); @@ -1745,8 +1836,8 @@ static void qpnp_hap_worker(struct work_struct *work) if (hap->vcc_pon && !hap->state && hap->vcc_pon_enabled) { rc = regulator_disable(hap->vcc_pon); if (rc) - pr_err("%s: could not disable vcc_pon regulator rc=%d\n", - __func__, rc); + pr_err("could not disable vcc_pon regulator rc=%d\n", + rc); else hap->vcc_pon_enabled = false; } @@ -1810,57 +1901,25 @@ static SIMPLE_DEV_PM_OPS(qpnp_haptic_pm_ops, qpnp_haptic_suspend, NULL); /* Configuration api for haptics registers */ static int qpnp_hap_config(struct qpnp_hap *hap) { - u8 reg = 0, unlock_val; + u8 val = 0; u32 temp; int rc, i; - uint error_code = 0; /* * This denotes the percentage error in rc clock multiplied by 10 */ u8 rc_clk_err_percent_x10; - /* Configure the ACTUATOR TYPE register */ - rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_ACT_TYPE_REG(hap->base)); - if (rc < 0) - return rc; - reg &= QPNP_HAP_ACT_TYPE_MASK; - reg |= hap->act_type; - rc = qpnp_hap_write_reg(hap, ®, QPNP_HAP_ACT_TYPE_REG(hap->base)); + /* Configure the CFG1 register for actuator type */ + rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_CFG1_REG(hap->base), + QPNP_HAP_ACT_TYPE_MASK, hap->act_type); if (rc) return rc; /* Configure auto resonance parameters */ - if (hap->act_type == QPNP_HAP_LRA) { - if (hap->lra_res_cal_period < QPNP_HAP_RES_CAL_PERIOD_MIN) - hap->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MIN; - else if (hap->lra_res_cal_period > QPNP_HAP_RES_CAL_PERIOD_MAX) - hap->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MAX; - - rc = qpnp_hap_read_reg(hap, ®, - QPNP_HAP_LRA_AUTO_RES_REG(hap->base)); - if (rc < 0) - return rc; - reg &= QPNP_HAP_AUTO_RES_MODE_MASK; - reg |= (hap->auto_res_mode << QPNP_HAP_AUTO_RES_MODE_SHIFT); - reg &= QPNP_HAP_LRA_HIGH_Z_MASK; - reg |= (hap->lra_high_z << QPNP_HAP_LRA_HIGH_Z_SHIFT); - reg &= QPNP_HAP_LRA_RES_CAL_PER_MASK; - temp = fls(hap->lra_res_cal_period) - 1; - reg |= (temp - 2); - rc = qpnp_hap_write_reg(hap, ®, - QPNP_HAP_LRA_AUTO_RES_REG(hap->base)); - if (rc) - return rc; - } else { - /* disable auto resonance for ERM */ - reg = 0x00; - - rc = qpnp_hap_write_reg(hap, ®, - QPNP_HAP_LRA_AUTO_RES_REG(hap->base)); - if (rc) - return rc; - } + rc = qpnp_hap_lra_auto_res_config(hap); + if (rc) + return rc; /* Configure the PLAY MODE register */ rc = qpnp_hap_play_mode_config(hap); @@ -1873,18 +1932,7 @@ static int qpnp_hap_config(struct qpnp_hap *hap) return rc; /* Configure the ILIM register */ - if (hap->ilim_ma < QPNP_HAP_ILIM_MIN_MA) - hap->ilim_ma = QPNP_HAP_ILIM_MIN_MA; - else if (hap->ilim_ma > QPNP_HAP_ILIM_MAX_MA) - hap->ilim_ma = QPNP_HAP_ILIM_MAX_MA; - - rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_ILIM_REG(hap->base)); - if (rc < 0) - return rc; - reg &= QPNP_HAP_ILIM_MASK; - temp = (hap->ilim_ma / QPNP_HAP_ILIM_MIN_MA) >> 1; - reg |= temp; - rc = qpnp_hap_write_reg(hap, ®, QPNP_HAP_ILIM_REG(hap->base)); + rc = qpnp_hap_ilim_config(hap); if (rc) return rc; @@ -1894,47 +1942,13 @@ static int qpnp_hap_config(struct qpnp_hap *hap) return rc; /* Configure the INTERNAL_PWM register */ - if (hap->int_pwm_freq_khz <= QPNP_HAP_INT_PWM_FREQ_253_KHZ) { - hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_253_KHZ; - temp = 0; - } else if (hap->int_pwm_freq_khz <= QPNP_HAP_INT_PWM_FREQ_505_KHZ) { - hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_505_KHZ; - temp = 1; - } else if (hap->int_pwm_freq_khz <= QPNP_HAP_INT_PWM_FREQ_739_KHZ) { - hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_739_KHZ; - temp = 2; - } else { - hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_1076_KHZ; - temp = 3; - } - - rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_INT_PWM_REG(hap->base)); - if (rc < 0) - return rc; - reg &= QPNP_HAP_INT_PWM_MASK; - reg |= temp; - rc = qpnp_hap_write_reg(hap, ®, QPNP_HAP_INT_PWM_REG(hap->base)); - if (rc) - return rc; - - rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_PWM_CAP_REG(hap->base)); - if (rc < 0) - return rc; - reg &= QPNP_HAP_INT_PWM_MASK; - reg |= temp; - rc = qpnp_hap_write_reg(hap, ®, QPNP_HAP_PWM_CAP_REG(hap->base)); + rc = qpnp_hap_int_pwm_config(hap); if (rc) return rc; /* Configure the WAVE SHAPE register */ - rc = qpnp_hap_read_reg(hap, ®, - QPNP_HAP_WAV_SHAPE_REG(hap->base)); - if (rc < 0) - return rc; - reg &= QPNP_HAP_WAV_SHAPE_MASK; - reg |= hap->wave_shape; - rc = qpnp_hap_write_reg(hap, ®, - QPNP_HAP_WAV_SHAPE_REG(hap->base)); + rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_CFG2_REG(hap->base), + QPNP_HAP_WAV_SHAPE_MASK, hap->wave_shape); if (rc) return rc; @@ -1955,35 +1969,24 @@ static int qpnp_hap_config(struct qpnp_hap *hap) * The frequency of 19.2Mzhz RC clock is subject to variation. Currently * a few PMI modules have MISC_TRIM_ERROR_RC19P2_CLK register * present in their MISC block. This register holds the frequency error - * in 19.2Mhz RC clock. + * in 19.2 MHz RC clock. */ if ((hap->act_type == QPNP_HAP_LRA) && hap->correct_lra_drive_freq - && hap->misc_trim_error_rc19p2_clk_reg_present) { - unlock_val = MISC_SEC_UNLOCK; - /* - * This SID value may change depending on the PMI chip where - * the MISC block is present. - */ - rc = regmap_write(hap->regmap, MISC_SEC_ACCESS, unlock_val); - if (rc) - dev_err(&hap->pdev->dev, - "Unable to do SEC_ACCESS rc:%d\n", rc); - - regmap_read(hap->regmap, MISC_TRIM_ERROR_RC19P2_CLK, - &error_code); - dev_dbg(&hap->pdev->dev, "TRIM register = 0x%x\n", error_code); + && hap->misc_clk_trim_error_reg) { + pr_debug("TRIM register = 0x%x\n", hap->clk_trim_error_code); /* * Extract the 4 LSBs and multiply by 7 to get * the %error in RC clock multiplied by 10 */ - rc_clk_err_percent_x10 = (error_code & 0x0F) * 7; + rc_clk_err_percent_x10 = (hap->clk_trim_error_code & 0x0F) * 7; /* * If the TRIM register holds value less than 0x80, * then there is a positive error in the RC clock. * If the TRIM register holds value greater than or equal to - * 0x80, then there is a negative error in the RC clock. + * 0x80, then there is a negative error in the RC clock. Bit 7 + * is the sign bit for error code. * * The adjusted play rate code is calculated as follows: * LRA drive period code (RATE_CFG) = @@ -1996,77 +1999,67 @@ static int qpnp_hap_config(struct qpnp_hap *hap) * Since 200KHz * 1/LRA drive frequency is already calculated * above we only do rest of the scaling here. */ - if (error_code >= 128) + if (hap->clk_trim_error_code & BIT(7)) LRA_DRIVE_PERIOD_NEG_ERR(hap, rc_clk_err_percent_x10); else LRA_DRIVE_PERIOD_POS_ERR(hap, rc_clk_err_percent_x10); } - dev_dbg(&hap->pdev->dev, - "Play rate code 0x%x\n", hap->init_drive_period_code); + pr_debug("Play rate code 0x%x\n", hap->init_drive_period_code); - reg = hap->init_drive_period_code & QPNP_HAP_RATE_CFG1_MASK; - rc = qpnp_hap_write_reg(hap, ®, - QPNP_HAP_RATE_CFG1_REG(hap->base)); + val = hap->init_drive_period_code & QPNP_HAP_RATE_CFG1_MASK; + rc = qpnp_hap_write_reg(hap, QPNP_HAP_RATE_CFG1_REG(hap->base), val); if (rc) return rc; - reg = (hap->init_drive_period_code & 0xF00) >> QPNP_HAP_RATE_CFG2_SHFT; - rc = qpnp_hap_write_reg(hap, ®, - QPNP_HAP_RATE_CFG2_REG(hap->base)); + val = (hap->init_drive_period_code & 0xF00) >> QPNP_HAP_RATE_CFG2_SHFT; + rc = qpnp_hap_write_reg(hap, QPNP_HAP_RATE_CFG2_REG(hap->base), val); if (rc) return rc; + hap->last_rate_cfg = hap->init_drive_period_code; + if (hap->act_type == QPNP_HAP_LRA && hap->perform_lra_auto_resonance_search) calculate_lra_code(hap); if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq) { hap->drive_period_code_max_limit = - (hap->init_drive_period_code * 100) / - (100 - hap->drive_period_code_max_limit_percent_variation); + (hap->init_drive_period_code * (100 + + hap->drive_period_code_max_limit_percent_variation)) + / 100; hap->drive_period_code_min_limit = - (hap->init_drive_period_code * 100) / - (100 + hap->drive_period_code_min_limit_percent_variation); - dev_dbg(&hap->pdev->dev, "Drive period code max limit %x\n" - "Drive period code min limit %x\n", - hap->drive_period_code_max_limit, - hap->drive_period_code_min_limit); + (hap->init_drive_period_code * (100 - + hap->drive_period_code_min_limit_percent_variation)) + / 100; + pr_debug("Drive period code max limit %x min limit %x\n", + hap->drive_period_code_max_limit, + hap->drive_period_code_min_limit); } /* Configure BRAKE register */ - rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_EN_CTL2_REG(hap->base)); - if (rc < 0) - return rc; - reg &= QPNP_HAP_BRAKE_MASK; - reg |= hap->en_brake; - rc = qpnp_hap_write_reg(hap, ®, QPNP_HAP_EN_CTL2_REG(hap->base)); + rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_EN_CTL2_REG(hap->base), + QPNP_HAP_BRAKE_MASK, (u8)hap->en_brake); if (rc) return rc; if (hap->en_brake && hap->sup_brake_pat) { - for (i = QPNP_HAP_BRAKE_PAT_LEN - 1, reg = 0; i >= 0; i--) { + for (i = QPNP_HAP_BRAKE_PAT_LEN - 1, val = 0; i >= 0; i--) { hap->brake_pat[i] &= QPNP_HAP_BRAKE_PAT_MASK; temp = i << 1; - reg |= hap->brake_pat[i] << temp; + val |= hap->brake_pat[i] << temp; } - rc = qpnp_hap_write_reg(hap, ®, - QPNP_HAP_BRAKE_REG(hap->base)); + rc = qpnp_hap_write_reg(hap, QPNP_HAP_BRAKE_REG(hap->base), + val); if (rc) return rc; } - /* Cache enable control register */ - rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_EN_CTL_REG(hap->base)); - if (rc < 0) - return rc; - hap->reg_en_ctl = reg; - /* Cache play register */ - rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_PLAY_REG(hap->base)); + rc = qpnp_hap_read_reg(hap, QPNP_HAP_PLAY_REG(hap->base), &val); if (rc < 0) return rc; - hap->reg_play = reg; + hap->reg_play = val; if (hap->play_mode == QPNP_HAP_BUFFER) rc = qpnp_hap_buffer_config(hap); @@ -2078,15 +2071,29 @@ static int qpnp_hap_config(struct qpnp_hap *hap) if (rc) return rc; + /* setup play irq */ + if (hap->play_irq >= 0) { + rc = devm_request_threaded_irq(&hap->pdev->dev, hap->play_irq, + NULL, qpnp_hap_play_irq, IRQF_ONESHOT, "qpnp_hap_play", + hap); + if (rc < 0) { + pr_err("Unable to request play(%d) IRQ(err:%d)\n", + hap->play_irq, rc); + return rc; + } + + /* use play_irq only for buffer mode */ + if (hap->play_mode != QPNP_HAP_BUFFER) + disable_irq(hap->play_irq); + } + /* setup short circuit irq */ - if (hap->use_sc_irq) { + if (hap->sc_irq >= 0) { rc = devm_request_threaded_irq(&hap->pdev->dev, hap->sc_irq, - NULL, qpnp_hap_sc_irq, - QPNP_IRQ_FLAGS, - "qpnp_sc_irq", hap); + NULL, qpnp_hap_sc_irq, IRQF_ONESHOT, "qpnp_hap_sc", + hap); if (rc < 0) { - dev_err(&hap->pdev->dev, - "Unable to request sc(%d) IRQ(err:%d)\n", + pr_err("Unable to request sc(%d) IRQ(err:%d)\n", hap->sc_irq, rc); return rc; } @@ -2101,18 +2108,46 @@ static int qpnp_hap_config(struct qpnp_hap *hap) static int qpnp_hap_parse_dt(struct qpnp_hap *hap) { struct platform_device *pdev = hap->pdev; + struct device_node *misc_node; struct property *prop; const char *temp_str; u32 temp; int rc; + if (of_find_property(pdev->dev.of_node, "qcom,pmic-misc", NULL)) { + misc_node = of_parse_phandle(pdev->dev.of_node, + "qcom,pmic-misc", 0); + if (!misc_node) + return -EINVAL; + + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,misc-clk-trim-error-reg", &temp); + if (rc < 0) { + pr_err("Missing misc-clk-trim-error-reg\n"); + return rc; + } + + if (!temp || temp > 0xFF) { + pr_err("Invalid misc-clk-trim-error-reg\n"); + return -EINVAL; + } + + hap->misc_clk_trim_error_reg = temp; + rc = qpnp_misc_read_reg(misc_node, hap->misc_clk_trim_error_reg, + &hap->clk_trim_error_code); + if (rc < 0) { + pr_err("Couldn't get clk_trim_error_code, rc=%d\n", rc); + return -EPROBE_DEFER; + } + } + hap->timeout_ms = QPNP_HAP_TIMEOUT_MS_MAX; rc = of_property_read_u32(pdev->dev.of_node, "qcom,timeout-ms", &temp); if (!rc) { hap->timeout_ms = temp; } else if (rc != -EINVAL) { - dev_err(&pdev->dev, "Unable to read timeout\n"); + pr_err("Unable to read timeout\n"); return rc; } @@ -2125,31 +2160,47 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) else if (strcmp(temp_str, "lra") == 0) hap->act_type = QPNP_HAP_LRA; else { - dev_err(&pdev->dev, "Invalid actuator type\n"); + pr_err("Invalid actuator type\n"); return -EINVAL; } } else if (rc != -EINVAL) { - dev_err(&pdev->dev, "Unable to read actuator type\n"); + pr_err("Unable to read actuator type\n"); return rc; } if (hap->act_type == QPNP_HAP_LRA) { - hap->auto_res_mode = QPNP_HAP_AUTO_RES_ZXD_EOP; rc = of_property_read_string(pdev->dev.of_node, "qcom,lra-auto-res-mode", &temp_str); if (!rc) { - if (strcmp(temp_str, "none") == 0) - hap->auto_res_mode = QPNP_HAP_AUTO_RES_NONE; - else if (strcmp(temp_str, "zxd") == 0) - hap->auto_res_mode = QPNP_HAP_AUTO_RES_ZXD; - else if (strcmp(temp_str, "qwd") == 0) - hap->auto_res_mode = QPNP_HAP_AUTO_RES_QWD; - else if (strcmp(temp_str, "max-qwd") == 0) - hap->auto_res_mode = QPNP_HAP_AUTO_RES_MAX_QWD; - else + if (hap->pmic_subtype == PM660_SUBTYPE) { + hap->auto_res_mode = + QPNP_HAP_PM660_AUTO_RES_QWD; + if (strcmp(temp_str, "zxd") == 0) + hap->auto_res_mode = + QPNP_HAP_PM660_AUTO_RES_ZXD; + else if (strcmp(temp_str, "qwd") == 0) + hap->auto_res_mode = + QPNP_HAP_PM660_AUTO_RES_QWD; + } else { hap->auto_res_mode = QPNP_HAP_AUTO_RES_ZXD_EOP; + if (strcmp(temp_str, "none") == 0) + hap->auto_res_mode = + QPNP_HAP_AUTO_RES_NONE; + else if (strcmp(temp_str, "zxd") == 0) + hap->auto_res_mode = + QPNP_HAP_AUTO_RES_ZXD; + else if (strcmp(temp_str, "qwd") == 0) + hap->auto_res_mode = + QPNP_HAP_AUTO_RES_QWD; + else if (strcmp(temp_str, "max-qwd") == 0) + hap->auto_res_mode = + QPNP_HAP_AUTO_RES_MAX_QWD; + else + hap->auto_res_mode = + QPNP_HAP_AUTO_RES_ZXD_EOP; + } } else if (rc != -EINVAL) { - dev_err(&pdev->dev, "Unable to read auto res mode\n"); + pr_err("Unable to read auto res mode\n"); return rc; } @@ -2159,6 +2210,11 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) if (!rc) { if (strcmp(temp_str, "none") == 0) hap->lra_high_z = QPNP_HAP_LRA_HIGH_Z_NONE; + if (hap->pmic_subtype == PM660_SUBTYPE) { + if (strcmp(temp_str, "opt0") == 0) + hap->lra_high_z = + QPNP_HAP_LRA_HIGH_Z_NONE; + } else if (strcmp(temp_str, "opt1") == 0) hap->lra_high_z = QPNP_HAP_LRA_HIGH_Z_OPT1; else if (strcmp(temp_str, "opt2") == 0) @@ -2166,20 +2222,33 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) else hap->lra_high_z = QPNP_HAP_LRA_HIGH_Z_OPT3; } else if (rc != -EINVAL) { - dev_err(&pdev->dev, "Unable to read LRA high-z\n"); + pr_err("Unable to read LRA high-z\n"); return rc; } + hap->lra_qwd_drive_duration = -EINVAL; + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,lra-qwd-drive-duration", + &hap->lra_qwd_drive_duration); + + hap->calibrate_at_eop = -EINVAL; + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,lra-calibrate-at-eop", &hap->calibrate_at_eop); + hap->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MAX; rc = of_property_read_u32(pdev->dev.of_node, "qcom,lra-res-cal-period", &temp); if (!rc) { hap->lra_res_cal_period = temp; } else if (rc != -EINVAL) { - dev_err(&pdev->dev, "Unable to read cal period\n"); + pr_err("Unable to read cal period\n"); return rc; } + hap->lra_hw_auto_resonance = + of_property_read_bool(pdev->dev.of_node, + "qcom,lra-hw-auto-resonance"); + hap->perform_lra_auto_resonance_search = of_property_read_bool(pdev->dev.of_node, "qcom,perform-lra-auto-resonance-search"); @@ -2202,10 +2271,6 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) hap->drive_period_code_min_limit_percent_variation = (u8) temp; - hap->misc_trim_error_rc19p2_clk_reg_present = - of_property_read_bool(pdev->dev.of_node, - "qcom,misc-trim-error-rc19p2-clk-reg-present"); - if (hap->auto_res_mode == QPNP_HAP_AUTO_RES_QWD) { hap->time_required_to_generate_back_emf_us = QPNP_HAP_TIME_REQ_FOR_BACK_EMF_GEN; @@ -2232,11 +2297,11 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) else if (strcmp(temp_str, "audio") == 0) hap->play_mode = QPNP_HAP_AUDIO; else { - dev_err(&pdev->dev, "Invalid play mode\n"); + pr_err("Invalid play mode\n"); return -EINVAL; } } else { - dev_err(&pdev->dev, "Unable to read play mode\n"); + pr_err("Unable to read play mode\n"); return rc; } @@ -2245,7 +2310,7 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) if (!rc) { hap->vmax_mv = temp; } else if (rc != -EINVAL) { - dev_err(&pdev->dev, "Unable to read vmax\n"); + pr_err("Unable to read vmax\n"); return rc; } @@ -2254,7 +2319,7 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) if (!rc) { hap->ilim_ma = temp; } else if (rc != -EINVAL) { - dev_err(&pdev->dev, "Unable to read ILim\n"); + pr_err("Unable to read ILim\n"); return rc; } @@ -2264,7 +2329,7 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) if (!rc) { hap->sc_deb_cycles = temp; } else if (rc != -EINVAL) { - dev_err(&pdev->dev, "Unable to read sc debounce\n"); + pr_err("Unable to read sc debounce\n"); return rc; } @@ -2274,7 +2339,7 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) if (!rc) { hap->int_pwm_freq_khz = temp; } else if (rc != -EINVAL) { - dev_err(&pdev->dev, "Unable to read int pwm freq\n"); + pr_err("Unable to read int pwm freq\n"); return rc; } @@ -2287,11 +2352,11 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) else if (strcmp(temp_str, "square") == 0) hap->wave_shape = QPNP_HAP_WAV_SQUARE; else { - dev_err(&pdev->dev, "Unsupported wav shape\n"); + pr_err("Unsupported wav shape\n"); return -EINVAL; } } else if (rc != -EINVAL) { - dev_err(&pdev->dev, "Unable to read wav shape\n"); + pr_err("Unable to read wav shape\n"); return rc; } @@ -2301,7 +2366,7 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) if (!rc) { hap->wave_play_rate_us = temp; } else if (rc != -EINVAL) { - dev_err(&pdev->dev, "Unable to read play rate\n"); + pr_err("Unable to read play rate\n"); return rc; } @@ -2320,9 +2385,9 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) prop = of_find_property(pdev->dev.of_node, "qcom,brake-pattern", &temp); if (!prop) { - dev_info(&pdev->dev, "brake pattern not found"); + pr_info("brake pattern not found"); } else if (temp != QPNP_HAP_BRAKE_PAT_LEN) { - dev_err(&pdev->dev, "Invalid len of brake pattern\n"); + pr_err("Invalid len of brake pattern\n"); return -EINVAL; } else { hap->sup_brake_pat = true; @@ -2331,14 +2396,14 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) } } - hap->use_sc_irq = of_property_read_bool(pdev->dev.of_node, - "qcom,use-sc-irq"); - if (hap->use_sc_irq) { - hap->sc_irq = platform_get_irq_byname(hap->pdev, "sc-irq"); - if (hap->sc_irq < 0) { - dev_err(&pdev->dev, "Unable to get sc irq\n"); - return hap->sc_irq; - } + hap->play_irq = platform_get_irq_byname(hap->pdev, "play-irq"); + if (hap->play_irq < 0) + pr_warn("Unable to get play irq\n"); + + hap->sc_irq = platform_get_irq_byname(hap->pdev, "sc-irq"); + if (hap->sc_irq < 0) { + pr_err("Unable to get sc irq\n"); + return hap->sc_irq; } if (of_find_property(pdev->dev.of_node, "vcc_pon-supply", NULL)) @@ -2347,6 +2412,34 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) return 0; } +static int qpnp_hap_get_pmic_revid(struct qpnp_hap *hap) +{ + struct pmic_revid_data *pmic_rev_id; + struct device_node *revid_dev_node; + + revid_dev_node = of_parse_phandle(hap->pdev->dev.of_node, + "qcom,pmic-revid", 0); + if (!revid_dev_node) { + pr_err("Missing qcom,pmic-revid property - driver failed\n"); + return -EINVAL; + } + pmic_rev_id = get_revid_data(revid_dev_node); + if (IS_ERR_OR_NULL(pmic_rev_id)) { + pr_err("Unable to get pmic_revid rc=%ld\n", + PTR_ERR(pmic_rev_id)); + /* + * the revid peripheral must be registered, any failure + * here only indicates that the rev-id module has not + * probed yet. + */ + return -EPROBE_DEFER; + } + + hap->pmic_subtype = pmic_rev_id->pmic_subtype; + + return 0; +} + static int qpnp_haptic_probe(struct platform_device *pdev) { struct qpnp_hap *hap; @@ -2359,7 +2452,7 @@ static int qpnp_haptic_probe(struct platform_device *pdev) return -ENOMEM; hap->regmap = dev_get_regmap(pdev->dev.parent, NULL); if (!hap->regmap) { - dev_err(&pdev->dev, "Couldn't get parent's regmap\n"); + pr_err("Couldn't get parent's regmap\n"); return -EINVAL; } @@ -2367,8 +2460,7 @@ static int qpnp_haptic_probe(struct platform_device *pdev) rc = of_property_read_u32(pdev->dev.of_node, "reg", &base); if (rc < 0) { - dev_err(&pdev->dev, - "Couldn't find reg in node = %s rc = %d\n", + pr_err("Couldn't find reg in node = %s rc = %d\n", pdev->dev.of_node->full_name, rc); return rc; } @@ -2376,15 +2468,22 @@ static int qpnp_haptic_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, hap); + rc = qpnp_hap_get_pmic_revid(hap); + if (rc) { + pr_err("Unable to check PMIC version rc=%d\n", rc); + return rc; + } + rc = qpnp_hap_parse_dt(hap); if (rc) { - dev_err(&pdev->dev, "DT parsing failed\n"); + pr_err("DT parsing failed\n"); return rc; } + spin_lock_init(&hap->bus_lock); rc = qpnp_hap_config(hap); if (rc) { - dev_err(&pdev->dev, "hap config failed\n"); + pr_err("hap config failed\n"); return rc; } @@ -2404,8 +2503,8 @@ static int qpnp_haptic_probe(struct platform_device *pdev) hap->timed_dev.get_time = qpnp_hap_get_time; hap->timed_dev.enable = qpnp_hap_td_enable; - if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq) { - INIT_WORK(&hap->auto_res_err_work, correct_auto_res_error); + if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq && + !hap->lra_hw_auto_resonance) { hrtimer_init(&hap->auto_res_err_poll_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); hap->auto_res_err_poll_timer.function = detect_auto_res_error; @@ -2413,7 +2512,7 @@ static int qpnp_haptic_probe(struct platform_device *pdev) rc = timed_output_dev_register(&hap->timed_dev); if (rc < 0) { - dev_err(&pdev->dev, "timed_output registration failed\n"); + pr_err("timed_output registration failed\n"); goto timed_output_fail; } @@ -2421,7 +2520,7 @@ static int qpnp_haptic_probe(struct platform_device *pdev) rc = sysfs_create_file(&hap->timed_dev.dev->kobj, &qpnp_hap_attrs[i].attr); if (rc < 0) { - dev_err(&pdev->dev, "sysfs creation failed\n"); + pr_err("sysfs creation failed\n"); goto sysfs_fail; } } @@ -2430,8 +2529,7 @@ static int qpnp_haptic_probe(struct platform_device *pdev) vcc_pon = regulator_get(&pdev->dev, "vcc_pon"); if (IS_ERR(vcc_pon)) { rc = PTR_ERR(vcc_pon); - dev_err(&pdev->dev, - "regulator get failed vcc_pon rc=%d\n", rc); + pr_err("regulator get failed vcc_pon rc=%d\n", rc); goto sysfs_fail; } hap->vcc_pon = vcc_pon; @@ -2448,7 +2546,8 @@ sysfs_fail: timed_output_dev_unregister(&hap->timed_dev); timed_output_fail: cancel_work_sync(&hap->work); - if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq) + if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq && + !hap->lra_hw_auto_resonance) hrtimer_cancel(&hap->auto_res_err_poll_timer); hrtimer_cancel(&hap->hap_timer); mutex_destroy(&hap->lock); @@ -2467,7 +2566,8 @@ static int qpnp_haptic_remove(struct platform_device *pdev) &qpnp_hap_attrs[i].attr); cancel_work_sync(&hap->work); - if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq) + if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq && + !hap->lra_hw_auto_resonance) hrtimer_cancel(&hap->auto_res_err_poll_timer); hrtimer_cancel(&hap->hap_timer); timed_output_dev_unregister(&hap->timed_dev); |
