diff --git a/Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt b/Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt index 337649824257..aa3363b52a03 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt @@ -76,6 +76,10 @@ Optional properties when qcom,actuator-type is "lra" at End of Pattern - qcom,lra-res-cal-period : Auto resonance calibration period. The values range from 4 to 32(default) +- qcom,lra-auto-mode : If this property is specified, haptics mode for LRA + actuators will be automatically configured along with + other required settings runtime based on the duration + of the pattern. - qcom,perform-lra-auto-resonance-search : boolean, define this property if: a) the underlying PMI chip does not have a register in the MISC block to read the error percentage in RC clock diff --git a/drivers/soc/qcom/qpnp-haptic.c b/drivers/soc/qcom/qpnp-haptic.c index 70cf11359e97..d86f8671705a 100644 --- a/drivers/soc/qcom/qpnp-haptic.c +++ b/drivers/soc/qcom/qpnp-haptic.c @@ -85,6 +85,7 @@ #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_OVD_BIT BIT(6) #define QPNP_HAP_VMAX_MASK GENMASK(5, 1) #define QPNP_HAP_VMAX_SHIFT 1 #define QPNP_HAP_VMAX_MIN_MV 116 @@ -117,6 +118,8 @@ #define QPNP_HAP_WAV_REP_MAX 128 #define QPNP_HAP_WAV_S_REP_MIN 1 #define QPNP_HAP_WAV_S_REP_MAX 8 +#define QPNP_HAP_WF_AMP_MASK GENMASK(5, 1) +#define QPNP_HAP_WF_OVD_BIT BIT(6) #define QPNP_HAP_BRAKE_PAT_MASK 0x3 #define QPNP_HAP_ILIM_MIN_MA 400 #define QPNP_HAP_ILIM_MAX_MA 800 @@ -135,21 +138,20 @@ #define QPNP_HAP_WAV_SINE 0 #define QPNP_HAP_WAV_SQUARE 1 #define QPNP_HAP_WAV_SAMP_LEN 8 -#define QPNP_HAP_WAV_SAMP_MAX 0x7E +#define QPNP_HAP_WAV_SAMP_MAX 0x3E #define QPNP_HAP_BRAKE_PAT_LEN 4 -#define QPNP_HAP_PLAY_EN 0x80 +#define QPNP_HAP_PLAY_EN_BIT BIT(7) #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 +#define SC_MAX_COUNT 5 #define QPNP_HAP_TIMEOUT_MS_MAX 15000 #define QPNP_HAP_STR_SIZE 20 #define QPNP_HAP_MAX_RETRIES 5 -#define QPNP_HAP_CYCLS 5 #define QPNP_TEST_TIMER_MS 5 #define QPNP_HAP_TIME_REQ_FOR_BACK_EMF_GEN 20000 @@ -261,6 +263,22 @@ struct qpnp_pwm_info { u32 period_us; }; +/* + * qpnp_hap_lra_ares_cfg - Haptic auto_resonance configuration + * @ lra_qwd_drive_duration - LRA QWD drive duration + * @ calibrate_at_eop - Calibrate at EOP + * @ lra_res_cal_period - LRA resonance calibration period + * @ auto_res_mode - auto resonace mode + * @ lra_high_z - high z option line + */ +struct qpnp_hap_lra_ares_cfg { + int lra_qwd_drive_duration; + int calibrate_at_eop; + enum qpnp_hap_high_z lra_high_z; + u16 lra_res_cal_period; + u8 auto_res_mode; +}; + /* * qpnp_hap - Haptic data structure * @ spmi - spmi device @@ -270,6 +288,7 @@ struct qpnp_pwm_info { * @ work - worker * @ sc_work - worker to handle short circuit condition * @ pwm_info - pwm info + * @ ares_cfg - auto resonance configuration * @ lock - mutex lock * @ wf_lock - mutex lock for waveform * @ init_drive_period_code - the initial lra drive period code @@ -281,10 +300,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 * @ timeout_ms - max timeout in ms * @ time_required_to_generate_back_emf_us - the time required for sufficient back-emf to be generated for auto resonance to be successful @@ -293,6 +309,7 @@ struct qpnp_pwm_info { * @ sc_deb_cycles - short circuit debounce cycles * @ int_pwm_freq_khz - internal pwm frequency in khz * @ wave_play_rate_us - play rate for waveform + * @ play_time_ms - play time set by the user * @ ext_pwm_freq_khz - external pwm frequency in khz * @ wave_rep_cnt - waveform repeat count * @ wave_s_rep_cnt - waveform sample repeat count @@ -305,14 +322,12 @@ struct qpnp_pwm_info { * @ wave_samp - array of wave samples * @ shadow_wave_samp - shadow array of wave samples * @ brake_pat - pattern for active breaking - * @ reg_play - play register - * @ lra_res_cal_period - period for resonance calibration - * @ sc_duration - counter to determine the duration of short circuit condition + * @ sc_count - counter to determine the duration of short circuit condition * @ lra_hw_auto_resonance - enable hardware auto resonance * @ state - current state of haptics + * @ module_en - haptics module enable status * @ 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 @@ -320,6 +335,9 @@ struct qpnp_pwm_info { * @ 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. + * @ auto_mode - Auto mode selection + * @ override_auto_mode_config - Flag to override auto mode configuration with + * user specified values through sysfs. */ struct qpnp_hap { struct platform_device *pdev; @@ -333,14 +351,12 @@ struct qpnp_hap { struct hrtimer hap_test_timer; struct work_struct test_work; struct qpnp_pwm_info pwm_info; + struct qpnp_hap_lra_ares_cfg ares_cfg; struct mutex lock; struct mutex wf_lock; spinlock_t bus_lock; struct completion completion; enum qpnp_hap_mode play_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; @@ -350,6 +366,7 @@ struct qpnp_hap { u32 sc_deb_cycles; u32 int_pwm_freq_khz; u32 wave_play_rate_us; + u32 play_time_ms; u32 ext_pwm_freq_khz; u32 wave_rep_cnt; u32 wave_s_rep_cnt; @@ -360,7 +377,6 @@ struct qpnp_hap { 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; @@ -368,23 +384,24 @@ 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_play; - u8 sc_duration; + u8 sc_count; 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 module_en; bool manage_pon_supply; bool wf_update; bool pwm_cfg_state; - bool buffer_cfg_state; bool en_brake; bool sup_brake_pat; bool correct_lra_drive_freq; bool perform_lra_auto_resonance_search; + bool auto_mode; + bool override_auto_mode_config; + bool play_irq_en; }; static struct qpnp_hap *ghap; @@ -502,36 +519,50 @@ static void qpnp_handle_sc_irq(struct work_struct *work) /* clear short circuit register */ if (val & SC_FOUND_BIT) { - hap->sc_duration++; + hap->sc_count++; val = QPNP_HAP_SC_CLR; qpnp_hap_write_reg(hap, QPNP_HAP_SC_CLR_REG(hap->base), val); } } +#define QPNP_HAP_CYCLES 4 static int qpnp_hap_mod_enable(struct qpnp_hap *hap, bool on) { + unsigned long wait_time_us; u8 val; int rc, i; - 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; + if (hap->module_en == on) + return 0; + if (!on) { + /* + * Wait for 4 cycles of play rate for play time is > 20 ms and + * wait for play time when play time is < 20 ms. This way, there + * will be an improvement in waiting time polling BUSY status. + */ + if (hap->play_time_ms <= 20) + wait_time_us = hap->play_time_ms * 1000; + else + wait_time_us = QPNP_HAP_CYCLES * hap->wave_play_rate_us; + + for (i = 0; i < QPNP_HAP_MAX_RETRIES; i++) { rc = qpnp_hap_read_reg(hap, QPNP_HAP_STATUS(hap->base), &val); + if (rc < 0) + return rc; pr_debug("HAP_STATUS=0x%x\n", val); - /* wait for QPNP_HAP_CYCLS cycles of play rate */ + /* wait for play_rate cycles */ if (val & QPNP_HAP_STATUS_BUSY) { - usleep_range(sleep_time, sleep_time + 1); + usleep_range(wait_time_us, wait_time_us + 1); if (hap->play_mode == QPNP_HAP_DIRECT || hap->play_mode == QPNP_HAP_PWM) break; - } else + } else { break; + } } if (i >= QPNP_HAP_MAX_RETRIES) @@ -543,27 +574,18 @@ static int qpnp_hap_mod_enable(struct qpnp_hap *hap, bool on) if (rc < 0) return rc; + hap->module_en = on; return 0; } -static int qpnp_hap_play(struct qpnp_hap *hap, int on) +static int qpnp_hap_play(struct qpnp_hap *hap, bool on) { u8 val; int rc; - val = hap->reg_play; - if (on) - val |= QPNP_HAP_PLAY_EN; - else - val &= ~QPNP_HAP_PLAY_EN; - + val = on ? QPNP_HAP_PLAY_EN_BIT : 0; rc = qpnp_hap_write_reg(hap, QPNP_HAP_PLAY_REG(hap->base), val); - if (rc < 0) - return rc; - - hap->reg_play = val; - - return 0; + return rc; } /* sysfs show debug registers */ @@ -624,13 +646,13 @@ static irqreturn_t qpnp_hap_sc_irq(int irq, void *_hap) pr_debug("Short circuit detected\n"); - if (hap->sc_duration < SC_MAX_DURATION) { + if (hap->sc_count < SC_MAX_COUNT) { 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); else - hap->sc_duration = 0; + hap->sc_count = 0; } else { /* Disable haptics module if the duration of short circuit * exceeds the maximum limit (5 secs). @@ -645,9 +667,11 @@ 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) +static int qpnp_hap_buffer_config(struct qpnp_hap *hap, u8 *wave_samp, + bool overdrive) { - u8 val = 0; + u8 buf[QPNP_HAP_WAV_SAMP_LEN], val; + u8 *ptr; int rc, i; /* Configure the WAVE_REPEAT register */ @@ -668,16 +692,27 @@ static int qpnp_hap_buffer_config(struct qpnp_hap *hap) if (rc) return rc; + /* Don't set override bit in waveform sample for PM660 */ + if (hap->pmic_subtype == PM660_SUBTYPE) + overdrive = false; + + if (wave_samp) + ptr = wave_samp; + else + ptr = hap->wave_samp; + /* Configure WAVE_SAMPLE1 to WAVE_SAMPLE8 register */ - 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; + for (i = 0; i < QPNP_HAP_WAV_SAMP_LEN; i++) { + buf[i] = ptr[i] & QPNP_HAP_WF_AMP_MASK; + if (buf[i]) + buf[i] |= (overdrive ? QPNP_HAP_WF_OVD_BIT : 0); } - hap->buffer_cfg_state = true; + rc = qpnp_hap_write_mult_reg(hap, QPNP_HAP_WAV_S_REG_BASE(hap->base), + buf, QPNP_HAP_WAV_SAMP_LEN); + if (rc) + return rc; + return 0; } @@ -736,10 +771,12 @@ static int qpnp_hap_pwm_config(struct qpnp_hap *hap) return 0; } -static int qpnp_hap_lra_auto_res_config(struct qpnp_hap *hap) +static int qpnp_hap_lra_auto_res_config(struct qpnp_hap *hap, + struct qpnp_hap_lra_ares_cfg *tmp_cfg) { + struct qpnp_hap_lra_ares_cfg *ares_cfg; int rc; - u8 val, mask; + u8 val = 0, mask = 0; /* disable auto resonance for ERM */ if (hap->act_type == QPNP_HAP_ERM) { @@ -751,59 +788,73 @@ static int qpnp_hap_lra_auto_res_config(struct qpnp_hap *hap) 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, 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 (tmp_cfg) + ares_cfg = tmp_cfg; + else + ares_cfg = &hap->ares_cfg; + + if (ares_cfg->lra_res_cal_period < QPNP_HAP_RES_CAL_PERIOD_MIN) + ares_cfg->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MIN; if (hap->pmic_subtype == PM660_SUBTYPE) { - if (hap->lra_res_cal_period > + if (ares_cfg->lra_res_cal_period > QPNP_HAP_PM660_RES_CAL_PERIOD_MAX) - hap->lra_res_cal_period = + ares_cfg->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; + if (ares_cfg->auto_res_mode == QPNP_HAP_PM660_AUTO_RES_QWD) + ares_cfg->lra_res_cal_period = 0; + + if (ares_cfg->lra_res_cal_period) + val = ilog2(ares_cfg->lra_res_cal_period / + QPNP_HAP_RES_CAL_PERIOD_MIN) + 1; } else { - if (hap->lra_res_cal_period > QPNP_HAP_RES_CAL_PERIOD_MAX) - hap->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MAX; + if (ares_cfg->lra_res_cal_period > QPNP_HAP_RES_CAL_PERIOD_MAX) + ares_cfg->lra_res_cal_period = + QPNP_HAP_RES_CAL_PERIOD_MAX; + + if (ares_cfg->lra_res_cal_period) + val = ilog2(ares_cfg->lra_res_cal_period / + QPNP_HAP_RES_CAL_PERIOD_MIN); } - 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 << + val |= ares_cfg->auto_res_mode << QPNP_HAP_PM660_AUTO_RES_MODE_SHIFT; mask = QPNP_HAP_PM660_AUTO_RES_MODE_BIT; - val |= hap->lra_high_z << + val |= ares_cfg->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 << + if (ares_cfg->lra_qwd_drive_duration != -EINVAL) { + val |= ares_cfg->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 << + if (ares_cfg->calibrate_at_eop != -EINVAL) { + val |= ares_cfg->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); + val |= (ares_cfg->auto_res_mode << + QPNP_HAP_AUTO_RES_MODE_SHIFT); + val |= (ares_cfg->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; } + pr_debug("mode: %d hi_z period: %d cal_period: %d\n", + ares_cfg->auto_res_mode, ares_cfg->lra_high_z, + ares_cfg->lra_res_cal_period); + rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_LRA_AUTO_RES_REG(hap->base), mask, val); return rc; @@ -822,19 +873,29 @@ static int qpnp_hap_play_mode_config(struct qpnp_hap *hap) } /* configuration api for max voltage */ -static int qpnp_hap_vmax_config(struct qpnp_hap *hap) +static int qpnp_hap_vmax_config(struct qpnp_hap *hap, int vmax_mv, + bool overdrive) { 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; + if (vmax_mv < 0) + return -EINVAL; - val = (hap->vmax_mv / QPNP_HAP_VMAX_MIN_MV) << QPNP_HAP_VMAX_SHIFT; + /* Allow setting override bit in VMAX_CFG only for PM660 */ + if (hap->pmic_subtype != PM660_SUBTYPE) + overdrive = false; + + if (vmax_mv < QPNP_HAP_VMAX_MIN_MV) + vmax_mv = QPNP_HAP_VMAX_MIN_MV; + else if (vmax_mv > QPNP_HAP_VMAX_MAX_MV) + vmax_mv = QPNP_HAP_VMAX_MAX_MV; + + val = (vmax_mv / QPNP_HAP_VMAX_MIN_MV) << QPNP_HAP_VMAX_SHIFT; + if (overdrive) + val |= QPNP_HAP_VMAX_OVD_BIT; rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_VMAX_REG(hap->base), - QPNP_HAP_VMAX_MASK, val); + QPNP_HAP_VMAX_MASK | QPNP_HAP_VMAX_OVD_BIT, val); return rc; } @@ -912,6 +973,41 @@ static int qpnp_hap_int_pwm_config(struct qpnp_hap *hap) return rc; } +static int qpnp_hap_brake_config(struct qpnp_hap *hap, u8 *brake_pat) +{ + int rc, i; + u32 temp; + u8 *pat_ptr, val; + + if (!hap->en_brake) + return 0; + + /* Configure BRAKE register */ + 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 (!brake_pat) + pat_ptr = hap->brake_pat; + else + pat_ptr = brake_pat; + + if (hap->sup_brake_pat) { + for (i = QPNP_HAP_BRAKE_PAT_LEN - 1, val = 0; i >= 0; i--) { + pat_ptr[i] &= QPNP_HAP_BRAKE_PAT_MASK; + temp = i << 1; + val |= pat_ptr[i] << temp; + } + rc = qpnp_hap_write_reg(hap, QPNP_HAP_BRAKE_REG(hap->base), + val); + if (rc) + return rc; + } + + return 0; +} + /* DT parsing api for buffer mode */ static int qpnp_hap_parse_buffer_dt(struct qpnp_hap *hap) { @@ -920,6 +1016,9 @@ static int qpnp_hap_parse_buffer_dt(struct qpnp_hap *hap) u32 temp; int rc, i; + if (hap->wave_rep_cnt > 0 || hap->wave_s_rep_cnt > 0) + return 0; + hap->wave_rep_cnt = QPNP_HAP_WAV_REP_MIN; rc = of_property_read_u32(pdev->dev.of_node, "qcom,wave-rep-cnt", &temp); @@ -1251,6 +1350,25 @@ static ssize_t qpnp_hap_wf_s_rep_store(struct device *dev, return count; } +static int parse_string(const char *in_buf, char *out_buf) +{ + int i; + + if (snprintf(out_buf, QPNP_HAP_STR_SIZE, "%s", in_buf) + > QPNP_HAP_STR_SIZE) + return -EINVAL; + + for (i = 0; i < strlen(out_buf); i++) { + if (out_buf[i] == ' ' || out_buf[i] == '\n' || + out_buf[i] == '\t') { + out_buf[i] = '\0'; + break; + } + } + + return 0; +} + /* sysfs store function for play mode*/ static ssize_t qpnp_hap_play_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1259,17 +1377,12 @@ static ssize_t qpnp_hap_play_mode_store(struct device *dev, struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, timed_dev); char str[QPNP_HAP_STR_SIZE + 1]; - int rc = 0, temp, old_mode, i; + int rc = 0, temp, old_mode; - if (snprintf(str, QPNP_HAP_STR_SIZE, "%s", buf) > QPNP_HAP_STR_SIZE) - return -EINVAL; + rc = parse_string(buf, str); + if (rc < 0) + return rc; - for (i = 0; i < strlen(str); i++) { - if (str[i] == ' ' || str[i] == '\n' || str[i] == '\t') { - str[i] = '\0'; - break; - } - } if (strcmp(str, "buffer") == 0) temp = QPNP_HAP_BUFFER; else if (strcmp(str, "direct") == 0) @@ -1284,10 +1397,10 @@ static ssize_t qpnp_hap_play_mode_store(struct device *dev, if (temp == hap->play_mode) return count; - if (temp == QPNP_HAP_BUFFER && !hap->buffer_cfg_state) { + if (temp == QPNP_HAP_BUFFER) { rc = qpnp_hap_parse_buffer_dt(hap); if (!rc) - rc = qpnp_hap_buffer_config(hap); + rc = qpnp_hap_buffer_config(hap, NULL, false); } else if (temp == QPNP_HAP_PWM && !hap->pwm_cfg_state) { rc = qpnp_hap_parse_pwm_dt(hap); if (!rc) @@ -1436,6 +1549,245 @@ static ssize_t qpnp_hap_ramp_test_data_show(struct device *dev, } +static ssize_t qpnp_hap_auto_res_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct timed_output_dev *timed_dev = dev_get_drvdata(dev); + struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, + timed_dev); + char *str; + + if (hap->pmic_subtype == PM660_SUBTYPE) { + switch (hap->ares_cfg.auto_res_mode) { + case QPNP_HAP_PM660_AUTO_RES_ZXD: + str = "ZXD"; + break; + case QPNP_HAP_PM660_AUTO_RES_QWD: + str = "QWD"; + break; + default: + str = "None"; + break; + } + } else { + switch (hap->ares_cfg.auto_res_mode) { + case QPNP_HAP_AUTO_RES_NONE: + str = "None"; + break; + case QPNP_HAP_AUTO_RES_ZXD: + str = "ZXD"; + break; + case QPNP_HAP_AUTO_RES_QWD: + str = "QWD"; + break; + case QPNP_HAP_AUTO_RES_MAX_QWD: + str = "MAX_QWD"; + break; + case QPNP_HAP_AUTO_RES_ZXD_EOP: + str = "ZXD_EOP"; + break; + default: + str = "None"; + break; + } + } + + return snprintf(buf, PAGE_SIZE, "%s\n", str); +} + +static ssize_t qpnp_hap_auto_res_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct timed_output_dev *timed_dev = dev_get_drvdata(dev); + struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, + timed_dev); + char str[QPNP_HAP_STR_SIZE + 1]; + int rc = 0, temp; + + rc = parse_string(buf, str); + if (rc < 0) + return rc; + + if (hap->pmic_subtype == PM660_SUBTYPE) { + if (strcmp(str, "ZXD") == 0 || + strcmp(str, "zxd") == 0) + temp = QPNP_HAP_PM660_AUTO_RES_ZXD; + else if (strcmp(str, "QWD") == 0 || + strcmp(str, "qwd") == 0) + temp = QPNP_HAP_PM660_AUTO_RES_QWD; + else { + pr_err("Should be ZXD or QWD\n"); + return -EINVAL; + } + } else { + if (strcmp(str, "None") == 0) + temp = QPNP_HAP_AUTO_RES_NONE; + else if (strcmp(str, "ZXD") == 0 || + strcmp(str, "zxd") == 0) + temp = QPNP_HAP_AUTO_RES_ZXD; + else if (strcmp(str, "QWD") == 0 || + strcmp(str, "qwd") == 0) + temp = QPNP_HAP_AUTO_RES_QWD; + else if (strcmp(str, "ZXD_EOP") == 0 || + strcmp(str, "zxd_eop") == 0) + temp = QPNP_HAP_AUTO_RES_ZXD_EOP; + else if (strcmp(str, "MAX_QWD") == 0 || + strcmp(str, "max_qwd") == 0) + temp = QPNP_HAP_AUTO_RES_MAX_QWD; + else { + pr_err("Should be None or ZXD or QWD or ZXD_EOP or MAX_QWD\n"); + return -EINVAL; + } + } + + hap->ares_cfg.auto_res_mode = temp; + return count; +} + +static ssize_t qpnp_hap_hi_z_period_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct timed_output_dev *timed_dev = dev_get_drvdata(dev); + struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, + timed_dev); + char *str; + + switch (hap->ares_cfg.lra_high_z) { + case QPNP_HAP_LRA_HIGH_Z_NONE: + str = "high_z_none"; + break; + case QPNP_HAP_LRA_HIGH_Z_OPT1: + str = "high_z_opt1"; + break; + case QPNP_HAP_LRA_HIGH_Z_OPT2: + str = "high_z_opt2"; + break; + case QPNP_HAP_LRA_HIGH_Z_OPT3: + str = "high_z_opt3"; + break; + } + + return snprintf(buf, PAGE_SIZE, "%s\n", str); +} + +static ssize_t qpnp_hap_hi_z_period_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + 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; + + rc = kstrtoint(buf, 10, &data); + if (rc) + return rc; + + if (data < QPNP_HAP_LRA_HIGH_Z_NONE + || data > QPNP_HAP_LRA_HIGH_Z_OPT3) { + pr_err("Invalid high Z configuration\n"); + return -EINVAL; + } + + hap->ares_cfg.lra_high_z = data; + return count; +} + +static ssize_t qpnp_hap_calib_period_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct timed_output_dev *timed_dev = dev_get_drvdata(dev); + struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, + timed_dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", + hap->ares_cfg.lra_res_cal_period); +} + +static ssize_t qpnp_hap_calib_period_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + 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; + + rc = kstrtoint(buf, 10, &data); + if (rc) + return rc; + + if (data < QPNP_HAP_RES_CAL_PERIOD_MIN) { + pr_err("Invalid auto resonance calibration period\n"); + return -EINVAL; + } + + if (hap->pmic_subtype == PM660_SUBTYPE) { + if (data > QPNP_HAP_PM660_RES_CAL_PERIOD_MAX) { + pr_err("Invalid auto resonance calibration period\n"); + return -EINVAL; + } + } else { + if (data > QPNP_HAP_RES_CAL_PERIOD_MAX) { + pr_err("Invalid auto resonance calibration period\n"); + return -EINVAL; + } + } + + hap->ares_cfg.lra_res_cal_period = data; + return count; +} + +static ssize_t qpnp_hap_override_auto_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct timed_output_dev *timed_dev = dev_get_drvdata(dev); + struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, + timed_dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", hap->override_auto_mode_config); +} + +static ssize_t qpnp_hap_override_auto_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + 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; + + rc = kstrtoint(buf, 10, &data); + if (rc) + return rc; + + hap->override_auto_mode_config = data; + return count; +} + +static ssize_t qpnp_hap_vmax_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct timed_output_dev *timed_dev = dev_get_drvdata(dev); + struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, + timed_dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", hap->vmax_mv); +} + +static ssize_t qpnp_hap_vmax_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + 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; + + rc = kstrtoint(buf, 10, &data); + if (rc) + return rc; + + hap->vmax_mv = data; + return count; +} + /* sysfs attributes */ static struct device_attribute qpnp_hap_attrs[] = { __ATTR(wf_s0, 0664, qpnp_hap_wf_s0_show, qpnp_hap_wf_s0_store), @@ -1457,6 +1809,16 @@ static struct device_attribute qpnp_hap_attrs[] = { qpnp_hap_ramp_test_data_store), __ATTR(min_max_test, 0664, qpnp_hap_min_max_test_data_show, qpnp_hap_min_max_test_data_store), + __ATTR(auto_res_mode, 0664, qpnp_hap_auto_res_mode_show, + qpnp_hap_auto_res_mode_store), + __ATTR(high_z_period, 0664, qpnp_hap_hi_z_period_show, + qpnp_hap_hi_z_period_store), + __ATTR(calib_period, 0664, qpnp_hap_calib_period_show, + qpnp_hap_calib_period_store), + __ATTR(override_auto_mode_config, 0664, + qpnp_hap_override_auto_mode_show, + qpnp_hap_override_auto_mode_store), + __ATTR(vmax_mv, 0664, qpnp_hap_vmax_show, qpnp_hap_vmax_store), }; static int calculate_lra_code(struct qpnp_hap *hap) @@ -1515,9 +1877,47 @@ static int calculate_lra_code(struct qpnp_hap *hap) static int qpnp_hap_auto_res_enable(struct qpnp_hap *hap, int enable) { int rc = 0; - u8 val; + u32 back_emf_delay_us = hap->time_required_to_generate_back_emf_us; + u8 val, auto_res_mode_qwd; + + if (hap->act_type != QPNP_HAP_LRA) + return 0; + + if (hap->pmic_subtype == PM660_SUBTYPE) + auto_res_mode_qwd = (hap->ares_cfg.auto_res_mode == + QPNP_HAP_PM660_AUTO_RES_QWD); + else + auto_res_mode_qwd = (hap->ares_cfg.auto_res_mode == + QPNP_HAP_AUTO_RES_QWD); + + /* + * Do not enable auto resonance if auto mode is enabled and auto + * resonance mode is QWD, meaning short pattern. + */ + if (hap->auto_mode && auto_res_mode_qwd && enable) { + pr_debug("auto_mode enabled, not enabling auto_res\n"); + return 0; + } + + if (!hap->correct_lra_drive_freq && !auto_res_mode_qwd) { + pr_debug("correct_lra_drive_freq: %d auto_res_mode_qwd: %d\n", + hap->correct_lra_drive_freq, auto_res_mode_qwd); + return 0; + } val = enable ? AUTO_RES_ENABLE : 0; + /* + * For auto resonance detection to work properly, sufficient back-emf + * has to be generated. In general, back-emf takes some time to build + * up. When the auto resonance mode is chosen as QWD, high-z will be + * applied for every LRA cycle and hence there won't be enough back-emf + * at the start-up. Hence, the motor needs to vibrate for few LRA cycles + * after the PLAY bit is asserted. Enable the auto resonance after + * 'time_required_to_generate_back_emf_us' is completed. + */ + if (enable) + usleep_range(back_emf_delay_us, back_emf_delay_us + 1); + if (hap->pmic_subtype == PM660_SUBTYPE) rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_AUTO_RES_CTRL(hap->base), @@ -1534,6 +1934,7 @@ static int qpnp_hap_auto_res_enable(struct qpnp_hap *hap, int enable) else hap->status_flags &= ~AUTO_RESONANCE_ENABLED; + pr_debug("auto_res %sabled\n", enable ? "en" : "dis"); return rc; } @@ -1617,65 +2018,57 @@ static enum hrtimer_restart detect_auto_res_error(struct hrtimer *timer) return HRTIMER_RESTART; } -/* set api for haptics */ -static int qpnp_hap_set(struct qpnp_hap *hap, int on) +static bool is_sw_lra_auto_resonance_control(struct qpnp_hap *hap) +{ + if (hap->act_type != QPNP_HAP_LRA) + return false; + + if (hap->lra_hw_auto_resonance) + return false; + + if (!hap->correct_lra_drive_freq) + return false; + + if (hap->auto_mode && hap->play_mode == QPNP_HAP_BUFFER) + return false; + + return true; +} + +/* set api for haptics */ +static int qpnp_hap_set(struct qpnp_hap *hap, bool on) { - u8 auto_res_mode_qwd; int rc = 0; unsigned long timeout_ns = POLL_TIME_AUTO_RES_ERR_NS; - u32 back_emf_delay_us = hap->time_required_to_generate_back_emf_us; if (hap->play_mode == QPNP_HAP_PWM) { - if (on) + if (on) { rc = pwm_enable(hap->pwm_info.pwm_dev); - else + if (rc < 0) + return rc; + } else { pwm_disable(hap->pwm_info.pwm_dev); + } } else if (hap->play_mode == QPNP_HAP_BUFFER || hap->play_mode == QPNP_HAP_DIRECT) { if (on) { - /* - * For auto resonance detection to work properly, - * sufficient back-emf has to be generated. In general, - * back-emf takes some time to build up. When the auto - * resonance mode is chosen as QWD, high-z will be - * applied for every LRA cycle and hence there won't be - * enough back-emf at the start-up. Hence, the motor - * needs to vibrate for few LRA cycles after the PLAY - * bit is asserted. So disable the auto resonance here - * 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 || - auto_res_mode_qwd)) - qpnp_hap_auto_res_enable(hap, 0); + rc = qpnp_hap_auto_res_enable(hap, 0); + if (rc < 0) + return rc; rc = qpnp_hap_mod_enable(hap, on); if (rc < 0) return rc; rc = qpnp_hap_play(hap, on); + if (rc < 0) + return rc; - if ((hap->act_type == QPNP_HAP_LRA) && - (hap->correct_lra_drive_freq || - auto_res_mode_qwd)) { - usleep_range(back_emf_delay_us, - (back_emf_delay_us + 1)); + rc = qpnp_hap_auto_res_enable(hap, 1); + if (rc < 0) + return rc; - rc = qpnp_hap_auto_res_enable(hap, 1); - if (rc < 0) - return rc; - } - if (hap->act_type == QPNP_HAP_LRA && - hap->correct_lra_drive_freq && - !hap->lra_hw_auto_resonance) { + if (is_sw_lra_auto_resonance_control(hap)) { /* * Start timer to poll Auto Resonance error bit */ @@ -1683,7 +2076,7 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on) hrtimer_cancel(&hap->auto_res_err_poll_timer); hrtimer_start(&hap->auto_res_err_poll_timer, ktime_set(0, timeout_ns), - HRTIMER_MODE_REL); + HRTIMER_MODE_REL); mutex_unlock(&hap->lock); } } else { @@ -1691,54 +2084,182 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on) if (rc < 0) return rc; - if (hap->act_type == QPNP_HAP_LRA && - hap->correct_lra_drive_freq && - (hap->status_flags & AUTO_RESONANCE_ENABLED) && - !hap->lra_hw_auto_resonance) { + if (is_sw_lra_auto_resonance_control(hap) && + (hap->status_flags & AUTO_RESONANCE_ENABLED)) update_lra_frequency(hap); - } rc = qpnp_hap_mod_enable(hap, on); - if (hap->act_type == QPNP_HAP_LRA && - hap->correct_lra_drive_freq && - !hap->lra_hw_auto_resonance) { + if (rc < 0) + return rc; + + if (is_sw_lra_auto_resonance_control(hap)) hrtimer_cancel(&hap->auto_res_err_poll_timer); - } } } return rc; } +static int qpnp_hap_auto_mode_config(struct qpnp_hap *hap, int time_ms) +{ + struct qpnp_hap_lra_ares_cfg ares_cfg; + enum qpnp_hap_mode old_play_mode; + u8 old_ares_mode; + u8 brake_pat[QPNP_HAP_BRAKE_PAT_LEN] = {0}; + u8 wave_samp[QPNP_HAP_WAV_SAMP_LEN] = {0}; + int rc, vmax_mv; + + /* For now, this is for LRA only */ + if (hap->act_type == QPNP_HAP_ERM) + return 0; + + old_ares_mode = hap->ares_cfg.auto_res_mode; + old_play_mode = hap->play_mode; + pr_debug("auto_mode, time_ms: %d\n", time_ms); + if (time_ms <= 20) { + wave_samp[0] = QPNP_HAP_WAV_SAMP_MAX; + wave_samp[1] = QPNP_HAP_WAV_SAMP_MAX; + if (time_ms > 15) + wave_samp[2] = QPNP_HAP_WAV_SAMP_MAX; + + /* short pattern */ + rc = qpnp_hap_parse_buffer_dt(hap); + if (!rc) + rc = qpnp_hap_buffer_config(hap, wave_samp, true); + if (rc < 0) { + pr_err("Error in configuring buffer mode %d\n", + rc); + return rc; + } + + ares_cfg.lra_high_z = QPNP_HAP_LRA_HIGH_Z_OPT1; + ares_cfg.lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MIN; + if (hap->pmic_subtype == PM660_SUBTYPE) { + ares_cfg.auto_res_mode = + QPNP_HAP_PM660_AUTO_RES_QWD; + ares_cfg.lra_qwd_drive_duration = 0; + ares_cfg.calibrate_at_eop = 0; + } else { + ares_cfg.auto_res_mode = QPNP_HAP_AUTO_RES_QWD; + ares_cfg.lra_qwd_drive_duration = -EINVAL; + ares_cfg.calibrate_at_eop = -EINVAL; + } + + vmax_mv = QPNP_HAP_VMAX_MAX_MV; + rc = qpnp_hap_vmax_config(hap, vmax_mv, true); + if (rc < 0) + return rc; + + rc = qpnp_hap_brake_config(hap, brake_pat); + if (rc < 0) + return rc; + + /* enable play_irq for buffer mode */ + if (hap->play_irq >= 0 && !hap->play_irq_en) { + enable_irq(hap->play_irq); + hap->play_irq_en = true; + } + + hap->play_mode = QPNP_HAP_BUFFER; + hap->wave_shape = QPNP_HAP_WAV_SQUARE; + } else { + /* long pattern */ + ares_cfg.lra_high_z = QPNP_HAP_LRA_HIGH_Z_OPT1; + if (hap->pmic_subtype == PM660_SUBTYPE) { + ares_cfg.auto_res_mode = + QPNP_HAP_PM660_AUTO_RES_ZXD; + ares_cfg.lra_res_cal_period = + QPNP_HAP_PM660_RES_CAL_PERIOD_MAX; + ares_cfg.lra_qwd_drive_duration = 0; + ares_cfg.calibrate_at_eop = 1; + } else { + ares_cfg.auto_res_mode = QPNP_HAP_AUTO_RES_ZXD_EOP; + ares_cfg.lra_res_cal_period = + QPNP_HAP_RES_CAL_PERIOD_MAX; + ares_cfg.lra_qwd_drive_duration = -EINVAL; + ares_cfg.calibrate_at_eop = -EINVAL; + } + + vmax_mv = hap->vmax_mv; + rc = qpnp_hap_vmax_config(hap, vmax_mv, false); + if (rc < 0) + return rc; + + brake_pat[0] = 0x3; + rc = qpnp_hap_brake_config(hap, brake_pat); + if (rc < 0) + return rc; + + /* enable play_irq for direct mode */ + if (hap->play_irq >= 0 && hap->play_irq_en) { + disable_irq(hap->play_irq); + hap->play_irq_en = false; + } + + hap->play_mode = QPNP_HAP_DIRECT; + hap->wave_shape = QPNP_HAP_WAV_SINE; + } + + if (hap->override_auto_mode_config) { + rc = qpnp_hap_lra_auto_res_config(hap, NULL); + } else { + hap->ares_cfg.auto_res_mode = ares_cfg.auto_res_mode; + rc = qpnp_hap_lra_auto_res_config(hap, &ares_cfg); + } + + if (rc < 0) { + hap->ares_cfg.auto_res_mode = old_ares_mode; + return rc; + } + + rc = qpnp_hap_play_mode_config(hap); + if (rc < 0) { + hap->play_mode = old_play_mode; + return rc; + } + + rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_CFG2_REG(hap->base), + QPNP_HAP_WAV_SHAPE_MASK, hap->wave_shape); + if (rc < 0) + return rc; + + return 0; +} + /* enable interface from timed output class */ -static void qpnp_hap_td_enable(struct timed_output_dev *dev, int value) +static void qpnp_hap_td_enable(struct timed_output_dev *dev, int time_ms) { struct qpnp_hap *hap = container_of(dev, struct qpnp_hap, timed_dev); + int rc; + + if (time_ms <= 0) + return; + + if (time_ms < 10) + time_ms = 10; mutex_lock(&hap->lock); - - if (hap->act_type == QPNP_HAP_LRA && - hap->correct_lra_drive_freq && - !hap->lra_hw_auto_resonance) + if (is_sw_lra_auto_resonance_control(hap)) hrtimer_cancel(&hap->auto_res_err_poll_timer); hrtimer_cancel(&hap->hap_timer); - if (value == 0) { - if (hap->state == 0) { + if (hap->auto_mode) { + rc = qpnp_hap_auto_mode_config(hap, time_ms); + if (rc < 0) { + pr_err("Unable to do auto mode config\n"); mutex_unlock(&hap->lock); return; } - hap->state = 0; - } else { - value = (value > hap->timeout_ms ? - hap->timeout_ms : value); - hap->state = 1; - hrtimer_start(&hap->hap_timer, - ktime_set(value / 1000, (value % 1000) * 1000000), - HRTIMER_MODE_REL); } + + time_ms = (time_ms > hap->timeout_ms ? hap->timeout_ms : time_ms); + hap->play_time_ms = time_ms; + hap->state = 1; + hrtimer_start(&hap->hap_timer, + ktime_set(time_ms / 1000, (time_ms % 1000) * 1000000), + HRTIMER_MODE_REL); mutex_unlock(&hap->lock); schedule_work(&hap->work); } @@ -1824,7 +2345,7 @@ static void qpnp_hap_worker(struct work_struct *work) /* Disable haptics module if the duration of short circuit * exceeds the maximum limit (5 secs). */ - if (hap->sc_duration == SC_MAX_DURATION) { + if (hap->sc_count >= SC_MAX_COUNT) { rc = qpnp_hap_write_reg(hap, QPNP_HAP_EN_CTL_REG(hap->base), val); } else { @@ -1890,7 +2411,7 @@ static int qpnp_haptic_suspend(struct device *dev) hrtimer_cancel(&hap->hap_timer); cancel_work_sync(&hap->work); /* turn-off haptic */ - qpnp_hap_set(hap, 0); + qpnp_hap_set(hap, false); return 0; } @@ -1902,8 +2423,7 @@ static SIMPLE_DEV_PM_OPS(qpnp_haptic_pm_ops, qpnp_haptic_suspend, NULL); static int qpnp_hap_config(struct qpnp_hap *hap) { u8 val = 0; - u32 temp; - int rc, i; + int rc; /* * This denotes the percentage error in rc clock multiplied by 10 @@ -1917,7 +2437,7 @@ static int qpnp_hap_config(struct qpnp_hap *hap) return rc; /* Configure auto resonance parameters */ - rc = qpnp_hap_lra_auto_res_config(hap); + rc = qpnp_hap_lra_auto_res_config(hap, NULL); if (rc) return rc; @@ -1927,7 +2447,7 @@ static int qpnp_hap_config(struct qpnp_hap *hap) return rc; /* Configure the VMAX register */ - rc = qpnp_hap_vmax_config(hap); + rc = qpnp_hap_vmax_config(hap, hap->vmax_mv, false); if (rc) return rc; @@ -2037,32 +2557,12 @@ static int qpnp_hap_config(struct qpnp_hap *hap) hap->drive_period_code_min_limit); } - /* Configure BRAKE register */ - 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, val = 0; i >= 0; i--) { - hap->brake_pat[i] &= QPNP_HAP_BRAKE_PAT_MASK; - temp = i << 1; - val |= hap->brake_pat[i] << temp; - } - rc = qpnp_hap_write_reg(hap, QPNP_HAP_BRAKE_REG(hap->base), - val); - if (rc) - return rc; - } - - /* Cache play register */ - rc = qpnp_hap_read_reg(hap, QPNP_HAP_PLAY_REG(hap->base), &val); + rc = qpnp_hap_brake_config(hap, NULL); if (rc < 0) return rc; - hap->reg_play = val; if (hap->play_mode == QPNP_HAP_BUFFER) - rc = qpnp_hap_buffer_config(hap); + rc = qpnp_hap_buffer_config(hap, NULL, false); else if (hap->play_mode == QPNP_HAP_PWM) rc = qpnp_hap_pwm_config(hap); else if (hap->play_mode == QPNP_HAP_AUDIO) @@ -2083,8 +2583,10 @@ static int qpnp_hap_config(struct qpnp_hap *hap) } /* use play_irq only for buffer mode */ - if (hap->play_mode != QPNP_HAP_BUFFER) + if (hap->play_mode != QPNP_HAP_BUFFER) { disable_irq(hap->play_irq); + hap->play_irq_en = false; + } } /* setup short circuit irq */ @@ -2099,7 +2601,7 @@ static int qpnp_hap_config(struct qpnp_hap *hap) } } - hap->sc_duration = 0; + hap->sc_count = 0; return rc; } @@ -2173,30 +2675,31 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) "qcom,lra-auto-res-mode", &temp_str); if (!rc) { if (hap->pmic_subtype == PM660_SUBTYPE) { - hap->auto_res_mode = + hap->ares_cfg.auto_res_mode = QPNP_HAP_PM660_AUTO_RES_QWD; if (strcmp(temp_str, "zxd") == 0) - hap->auto_res_mode = + hap->ares_cfg.auto_res_mode = QPNP_HAP_PM660_AUTO_RES_ZXD; else if (strcmp(temp_str, "qwd") == 0) - hap->auto_res_mode = + hap->ares_cfg.auto_res_mode = QPNP_HAP_PM660_AUTO_RES_QWD; } else { - hap->auto_res_mode = QPNP_HAP_AUTO_RES_ZXD_EOP; + hap->ares_cfg.auto_res_mode = + QPNP_HAP_AUTO_RES_ZXD_EOP; if (strcmp(temp_str, "none") == 0) - hap->auto_res_mode = + hap->ares_cfg.auto_res_mode = QPNP_HAP_AUTO_RES_NONE; else if (strcmp(temp_str, "zxd") == 0) - hap->auto_res_mode = + hap->ares_cfg.auto_res_mode = QPNP_HAP_AUTO_RES_ZXD; else if (strcmp(temp_str, "qwd") == 0) - hap->auto_res_mode = + hap->ares_cfg.auto_res_mode = QPNP_HAP_AUTO_RES_QWD; else if (strcmp(temp_str, "max-qwd") == 0) - hap->auto_res_mode = + hap->ares_cfg.auto_res_mode = QPNP_HAP_AUTO_RES_MAX_QWD; else - hap->auto_res_mode = + hap->ares_cfg.auto_res_mode = QPNP_HAP_AUTO_RES_ZXD_EOP; } } else if (rc != -EINVAL) { @@ -2204,42 +2707,48 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) return rc; } - hap->lra_high_z = QPNP_HAP_LRA_HIGH_Z_OPT3; + hap->ares_cfg.lra_high_z = QPNP_HAP_LRA_HIGH_Z_OPT3; rc = of_property_read_string(pdev->dev.of_node, "qcom,lra-high-z", &temp_str); if (!rc) { if (strcmp(temp_str, "none") == 0) - hap->lra_high_z = QPNP_HAP_LRA_HIGH_Z_NONE; + hap->ares_cfg.lra_high_z = + QPNP_HAP_LRA_HIGH_Z_NONE; + else if (strcmp(temp_str, "opt1") == 0) + hap->ares_cfg.lra_high_z = + QPNP_HAP_LRA_HIGH_Z_OPT1; + else if (strcmp(temp_str, "opt2") == 0) + hap->ares_cfg.lra_high_z = + QPNP_HAP_LRA_HIGH_Z_OPT2; + else + hap->ares_cfg.lra_high_z = + QPNP_HAP_LRA_HIGH_Z_OPT3; + if (hap->pmic_subtype == PM660_SUBTYPE) { if (strcmp(temp_str, "opt0") == 0) - hap->lra_high_z = + hap->ares_cfg.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) - hap->lra_high_z = QPNP_HAP_LRA_HIGH_Z_OPT2; - else - hap->lra_high_z = QPNP_HAP_LRA_HIGH_Z_OPT3; } else if (rc != -EINVAL) { pr_err("Unable to read LRA high-z\n"); return rc; } - hap->lra_qwd_drive_duration = -EINVAL; + hap->ares_cfg.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->ares_cfg.lra_qwd_drive_duration); - hap->calibrate_at_eop = -EINVAL; + hap->ares_cfg.calibrate_at_eop = -EINVAL; rc = of_property_read_u32(pdev->dev.of_node, - "qcom,lra-calibrate-at-eop", &hap->calibrate_at_eop); + "qcom,lra-calibrate-at-eop", + &hap->ares_cfg.calibrate_at_eop); - hap->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MAX; + hap->ares_cfg.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; + hap->ares_cfg.lra_res_cal_period = temp; } else if (rc != -EINVAL) { pr_err("Unable to read cal period\n"); return rc; @@ -2271,7 +2780,7 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) hap->drive_period_code_min_limit_percent_variation = (u8) temp; - if (hap->auto_res_mode == QPNP_HAP_AUTO_RES_QWD) { + if (hap->ares_cfg.auto_res_mode == QPNP_HAP_AUTO_RES_QWD) { hap->time_required_to_generate_back_emf_us = QPNP_HAP_TIME_REQ_FOR_BACK_EMF_GEN; rc = of_property_read_u32(pdev->dev.of_node, @@ -2409,6 +2918,8 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) if (of_find_property(pdev->dev.of_node, "vcc_pon-supply", NULL)) hap->manage_pon_supply = true; + hap->auto_mode = of_property_read_bool(pdev->dev.of_node, + "qcom,lra-auto-mode"); return 0; } @@ -2503,12 +3014,9 @@ 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 && - !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; - } + hrtimer_init(&hap->auto_res_err_poll_timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + hap->auto_res_err_poll_timer.function = detect_auto_res_error; rc = timed_output_dev_register(&hap->timed_dev); if (rc < 0) { @@ -2546,9 +3054,7 @@ 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 && - !hap->lra_hw_auto_resonance) - hrtimer_cancel(&hap->auto_res_err_poll_timer); + hrtimer_cancel(&hap->auto_res_err_poll_timer); hrtimer_cancel(&hap->hap_timer); mutex_destroy(&hap->lock); mutex_destroy(&hap->wf_lock); @@ -2566,9 +3072,7 @@ 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 && - !hap->lra_hw_auto_resonance) - hrtimer_cancel(&hap->auto_res_err_poll_timer); + hrtimer_cancel(&hap->auto_res_err_poll_timer); hrtimer_cancel(&hap->hap_timer); timed_output_dev_unregister(&hap->timed_dev); mutex_destroy(&hap->lock);