mirror of
https://github.com/torvalds/linux.git
synced 2026-08-02 13:22:02 +02:00
Merge "input: qcom-hv-haptics: parse devicetree effect in different functions"
This commit is contained in:
commit
e16bc87c61
|
|
@ -64,6 +64,10 @@
|
|||
#define AUTO_RES_ERROR_BIT BIT(1)
|
||||
#define HPRW_RDY_FAULT_BIT BIT(0)
|
||||
|
||||
/* Only for HAP525_HV */
|
||||
#define HAP_CFG_REAL_TIME_LRA_IMPEDANCE_REG 0x0E
|
||||
#define LRA_IMPEDANCE_MOHMS_LSB 200
|
||||
|
||||
#define HAP_CFG_INT_RT_STS_REG 0x10
|
||||
#define FIFO_EMPTY_BIT BIT(1)
|
||||
|
||||
|
|
@ -152,6 +156,15 @@
|
|||
#define EN_HW_RECOVERY_BIT BIT(1)
|
||||
#define SW_ERR_DRV_FREQ_BIT BIT(0)
|
||||
|
||||
#define HAP_CFG_ISC_CFG_REG 0x65
|
||||
#define ILIM_CC_EN_BIT BIT(7)
|
||||
/* Following bits are only for HAP525_HV */
|
||||
#define EN_SC_DET_P_HAP525_HV_BIT BIT(6)
|
||||
#define EN_SC_DET_N_HAP525_HV_BIT BIT(5)
|
||||
#define EN_IMP_DET_HAP525_HV_BIT BIT(4)
|
||||
#define ILIM_PULSE_DENSITY_MASK GENMASK(3, 2)
|
||||
#define ILIM_DENSITY_8_OVER_64_CYCLES 0
|
||||
|
||||
#define HAP_CFG_FAULT_CLR_REG 0x66
|
||||
#define SC_CLR_BIT BIT(2)
|
||||
#define AUTO_RES_ERR_CLR_BIT BIT(1)
|
||||
|
|
@ -176,6 +189,16 @@
|
|||
#define CAL_RC_CLK_AUTO_VAL 1
|
||||
#define CAL_RC_CLK_MANUAL_VAL 2
|
||||
|
||||
/* For HAP520_MV and HAP525_HV */
|
||||
#define HAP_CFG_ISC_CFG2_REG 0x77
|
||||
#define EN_SC_DET_P_HAP520_MV_BIT BIT(6)
|
||||
#define EN_SC_DET_N_HAP520_MV_BIT BIT(5)
|
||||
#define ISC_THRESH_HAP520_MV_MASK GENMASK(2, 0)
|
||||
#define ISC_THRESH_HAP520_MV_140MA 0x01
|
||||
#define ISC_THRESH_HAP525_HV_MASK GENMASK(4, 0)
|
||||
#define ISC_THRESH_HAP525_HV_125MA 0x11
|
||||
#define ISC_THRESH_HAP525_HV_250MA 0x12
|
||||
|
||||
/* These registers are only applicable for HAP520_MV */
|
||||
#define HAP_CFG_HW_CONFIG_REG 0x0D
|
||||
#define HV_HAP_DRIVER_BIT BIT(1)
|
||||
|
|
@ -188,6 +211,13 @@
|
|||
#define HAP_CFG_VHPWR_REG 0x84
|
||||
#define VHPWR_STEP_MV 32
|
||||
|
||||
/* Only for HAP525_HV */
|
||||
#define HAP_CFG_RT_LRA_IMPD_MEAS_CFG_REG 0xA4
|
||||
#define LRA_IMPEDANCE_MEAS_EN_BIT BIT(7)
|
||||
#define LRA_IMPEDANCE_MEAS_CURRENT_SEL_BIT BIT(0)
|
||||
#define CURRENT_SEL_VAL_125MA 0
|
||||
#define CURRENT_SEL_VAL_250MA 1
|
||||
|
||||
/* version register definitions for HAPTICS_PATTERN module */
|
||||
#define HAP_PTN_REVISION2_REG 0x01
|
||||
#define HAP_PTN_V1 0x1
|
||||
|
|
@ -275,6 +305,11 @@
|
|||
#define HAP_BOOST_CLAMP_REG 0x70
|
||||
#define CLAMP_5V_BIT BIT(0)
|
||||
|
||||
/* haptics SDAM registers offset definition */
|
||||
#define HAP_STATUS_DATA_MSB_SDAM_OFFSET 0x46
|
||||
#define HAP_LRA_NOMINAL_OHM_SDAM_OFFSET 0x75
|
||||
#define HAP_LRA_DETECTED_OHM_SDAM_OFFSET 0x76
|
||||
|
||||
/* constant parameters */
|
||||
#define SAMPLES_PER_PATTERN 8
|
||||
#define BRAKE_SAMPLE_COUNT 8
|
||||
|
|
@ -517,11 +552,13 @@ struct haptics_hw_config {
|
|||
u32 lra_min_mohms;
|
||||
u32 lra_max_mohms;
|
||||
u32 lra_open_mohms;
|
||||
u32 lra_measured_mohms;
|
||||
u32 preload_effect;
|
||||
u32 fifo_empty_thresh;
|
||||
u16 rc_clk_cal_count;
|
||||
enum drv_sig_shape drv_wf;
|
||||
bool is_erm;
|
||||
bool measure_lra_impedance;
|
||||
};
|
||||
|
||||
struct custom_fifo_data {
|
||||
|
|
@ -956,9 +993,6 @@ static int haptics_adjust_lra_period(struct haptics_chip *chip, u32 *t_lra_us)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* The offset of SDAM register which saves STATUS_DATA_MSB value */
|
||||
#define HAP_STATUS_DATA_MSB_SDAM_OFFSET 0x46
|
||||
|
||||
/* constant definitions for calculating TLRA */
|
||||
#define TLRA_AUTO_RES_ERR_NO_CAL_STEP_PSEC 1667000
|
||||
#define TLRA_AUTO_RES_NO_CAL_STEP_PSEC 3333000
|
||||
|
|
@ -3765,178 +3799,170 @@ static int haptics_create_debugfs(struct haptics_chip *chip)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int haptics_parse_per_effect_dt(struct haptics_chip *chip,
|
||||
static int haptics_parse_effect_pattern_data(struct haptics_chip *chip,
|
||||
struct device_node *node, struct haptics_effect *effect)
|
||||
{
|
||||
struct haptics_hw_config *config = &chip->config;
|
||||
u32 data[SAMPLES_PER_PATTERN * 3];
|
||||
int rc, tmp, i;
|
||||
|
||||
if (!effect)
|
||||
return -EINVAL;
|
||||
|
||||
rc = of_property_read_u32(node, "qcom,effect-id", &effect->id);
|
||||
if (rc < 0) {
|
||||
dev_err(chip->dev, "Read qcom,effect-id failed, rc=%d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
effect->vmax_mv = config->vmax_mv;
|
||||
rc = of_property_read_u32(node, "qcom,wf-vmax-mv", &tmp);
|
||||
if (rc < 0)
|
||||
dev_dbg(chip->dev, "Read qcom,wf-vmax-mv failed, rc=%d\n",
|
||||
rc);
|
||||
else
|
||||
effect->vmax_mv = tmp;
|
||||
|
||||
if (effect->vmax_mv > MAX_VMAX_MV) {
|
||||
dev_err(chip->dev, "qcom,wf-vmax-mv (%d) exceed the max value: %d\n",
|
||||
effect->vmax_mv, MAX_VMAX_MV);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
effect->t_lra_us = config->t_lra_us;
|
||||
tmp = of_property_count_elems_of_size(node,
|
||||
"qcom,wf-pattern-data", sizeof(u32));
|
||||
if (tmp <= 0) {
|
||||
dev_dbg(chip->dev, "qcom,wf-pattern-data is not defined properly for effect %d\n",
|
||||
effect->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tmp > SAMPLES_PER_PATTERN * 3) {
|
||||
dev_err(chip->dev, "Pattern src can only play 8 samples at max\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tmp > 0) {
|
||||
effect->pattern = devm_kzalloc(chip->dev,
|
||||
sizeof(*effect->pattern), GFP_KERNEL);
|
||||
if (!effect->pattern)
|
||||
return -ENOMEM;
|
||||
effect->pattern = devm_kzalloc(chip->dev,
|
||||
sizeof(*effect->pattern), GFP_KERNEL);
|
||||
if (!effect->pattern)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = of_property_read_u32_array(node,
|
||||
"qcom,wf-pattern-data", data, tmp);
|
||||
if (rc < 0) {
|
||||
dev_err(chip->dev, "Read wf-pattern-data failed, rc=%d\n",
|
||||
rc);
|
||||
return rc;
|
||||
rc = of_property_read_u32_array(node,
|
||||
"qcom,wf-pattern-data", data, tmp);
|
||||
if (rc < 0) {
|
||||
dev_err(chip->dev, "Read wf-pattern-data failed, rc=%d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
for (i = 0; i < tmp / 3; i++) {
|
||||
if (data[3 * i] > 0x1ff || data[3 * i + 1] > T_LRA_X_8
|
||||
|| data[3 * i + 2] > 1) {
|
||||
dev_err(chip->dev, "allowed tuples: [amplitude(<= 0x1ff) period(<=6(T_LRA_X_8)) f_lra_x2(0,1)]\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < tmp / 3; i++) {
|
||||
if (data[3 * i] > 0x1ff || data[3 * i + 1] > T_LRA_X_8
|
||||
|| data[3 * i + 2] > 1) {
|
||||
dev_err(chip->dev, "allowed tuples: [amplitude(<= 0x1ff) period(<=6(T_LRA_X_8)) f_lra_x2(0,1)]\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
effect->pattern->samples[i].amplitude =
|
||||
(u16)data[3 * i];
|
||||
effect->pattern->samples[i].period =
|
||||
(enum s_period)data[3 * i + 1];
|
||||
effect->pattern->samples[i].f_lra_x2 =
|
||||
(bool)data[3 * i + 2];
|
||||
}
|
||||
|
||||
effect->pattern->samples[i].amplitude =
|
||||
(u16)data[3 * i];
|
||||
effect->pattern->samples[i].period =
|
||||
(enum s_period)data[3 * i + 1];
|
||||
effect->pattern->samples[i].f_lra_x2 =
|
||||
(bool)data[3 * i + 2];
|
||||
}
|
||||
|
||||
effect->pattern->preload = of_property_read_bool(node,
|
||||
"qcom,wf-pattern-preload");
|
||||
/*
|
||||
* Use PATTERN1 src by default, effect with preloaded
|
||||
* pattern will use PATTERN2 by default and only the
|
||||
* 1st preloaded pattern will be served.
|
||||
*/
|
||||
effect->src = PATTERN1;
|
||||
if (effect->pattern->preload) {
|
||||
if (config->preload_effect != -EINVAL) {
|
||||
dev_err(chip->dev, "effect %d has been defined as preloaded\n",
|
||||
config->preload_effect);
|
||||
effect->pattern->preload = false;
|
||||
} else {
|
||||
config->preload_effect = effect->id;
|
||||
effect->src = PATTERN2;
|
||||
}
|
||||
effect->pattern->preload = of_property_read_bool(node,
|
||||
"qcom,wf-pattern-preload");
|
||||
/*
|
||||
* Use PATTERN1 src by default, effect with preloaded
|
||||
* pattern will use PATTERN2 by default and only the
|
||||
* 1st preloaded pattern will be served.
|
||||
*/
|
||||
effect->src = PATTERN1;
|
||||
if (effect->pattern->preload) {
|
||||
if (config->preload_effect != -EINVAL) {
|
||||
dev_err(chip->dev, "effect %d has been defined as preloaded\n",
|
||||
config->preload_effect);
|
||||
effect->pattern->preload = false;
|
||||
} else {
|
||||
config->preload_effect = effect->id;
|
||||
effect->src = PATTERN2;
|
||||
}
|
||||
}
|
||||
|
||||
tmp = of_property_count_u8_elems(node, "qcom,wf-fifo-data");
|
||||
if (tmp > 0) {
|
||||
effect->fifo = devm_kzalloc(chip->dev,
|
||||
sizeof(*effect->fifo), GFP_KERNEL);
|
||||
if (!effect->fifo)
|
||||
return -ENOMEM;
|
||||
if (config->is_erm)
|
||||
effect->pattern->play_rate_us = DEFAULT_ERM_PLAY_RATE_US;
|
||||
else
|
||||
effect->pattern->play_rate_us = config->t_lra_us;
|
||||
|
||||
effect->fifo->samples = devm_kcalloc(chip->dev,
|
||||
tmp, sizeof(u8), GFP_KERNEL);
|
||||
if (!effect->fifo->samples)
|
||||
return -ENOMEM;
|
||||
rc = of_property_read_u32(node, "qcom,wf-pattern-period-us", &tmp);
|
||||
if (rc < 0)
|
||||
dev_dbg(chip->dev, "Read qcom,wf-pattern-period-us failed, rc=%d\n",
|
||||
rc);
|
||||
else
|
||||
effect->pattern->play_rate_us = tmp;
|
||||
|
||||
rc = of_property_read_u8_array(node, "qcom,wf-fifo-data",
|
||||
effect->fifo->samples, tmp);
|
||||
if (rc < 0) {
|
||||
dev_err(chip->dev, "Read wf-fifo-data failed, rc=%d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
effect->fifo->num_s = tmp;
|
||||
}
|
||||
|
||||
if (!effect->pattern && !effect->fifo) {
|
||||
dev_err(chip->dev, "no pattern specified for effect %d\n",
|
||||
effect->id);
|
||||
if (effect->pattern->play_rate_us > TLRA_MAX_US) {
|
||||
dev_err(chip->dev, "qcom,wf-pattern-period-us (%d) exceed the max value: %d\n",
|
||||
effect->pattern->play_rate_us,
|
||||
TLRA_MAX_US);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (effect->pattern) {
|
||||
if (config->is_erm)
|
||||
effect->pattern->play_rate_us =
|
||||
DEFAULT_ERM_PLAY_RATE_US;
|
||||
else
|
||||
effect->pattern->play_rate_us = config->t_lra_us;
|
||||
|
||||
rc = of_property_read_u32(node, "qcom,wf-pattern-period-us",
|
||||
&tmp);
|
||||
if (rc < 0)
|
||||
dev_dbg(chip->dev, "Read qcom,wf-pattern-period-us failed, rc=%d\n",
|
||||
rc);
|
||||
else
|
||||
effect->pattern->play_rate_us = tmp;
|
||||
|
||||
if (effect->pattern->play_rate_us > TLRA_MAX_US) {
|
||||
dev_err(chip->dev, "qcom,wf-pattern-period-us (%d) exceed the max value: %d\n",
|
||||
effect->pattern->play_rate_us,
|
||||
TLRA_MAX_US);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
effect->pattern->play_length_us =
|
||||
get_pattern_play_length_us(effect->pattern);
|
||||
if (effect->pattern->play_length_us == -EINVAL) {
|
||||
dev_err(chip->dev, "get pattern play length failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (effect->fifo)
|
||||
dev_dbg(chip->dev, "Ignore FIFO data if pattern is specified!\n");
|
||||
|
||||
} else if (effect->fifo) {
|
||||
effect->fifo->period_per_s = T_LRA;
|
||||
rc = of_property_read_u32(node, "qcom,wf-fifo-period", &tmp);
|
||||
if (tmp > F_48KHZ) {
|
||||
dev_err(chip->dev, "FIFO playing period %d is not supported\n",
|
||||
tmp);
|
||||
return -EINVAL;
|
||||
} else if (!rc) {
|
||||
effect->fifo->period_per_s = tmp;
|
||||
}
|
||||
|
||||
effect->fifo->play_length_us =
|
||||
get_fifo_play_length_us(effect->fifo, config->t_lra_us);
|
||||
if (effect->fifo->play_length_us == -EINVAL) {
|
||||
dev_err(chip->dev, "get fifo play length failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
effect->src = FIFO;
|
||||
effect->fifo->preload = of_property_read_bool(node,
|
||||
"qcom,wf-fifo-preload");
|
||||
effect->pattern->play_length_us = get_pattern_play_length_us(effect->pattern);
|
||||
if (effect->pattern->play_length_us == -EINVAL) {
|
||||
dev_err(chip->dev, "get pattern play length failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int haptics_parse_effect_fifo_data(struct haptics_chip *chip,
|
||||
struct device_node *node, struct haptics_effect *effect)
|
||||
{
|
||||
struct haptics_hw_config *config = &chip->config;
|
||||
int rc, tmp;
|
||||
|
||||
if (effect->pattern) {
|
||||
dev_dbg(chip->dev, "ignore parsing FIFO effect when pattern effect is present\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp = of_property_count_u8_elems(node, "qcom,wf-fifo-data");
|
||||
if (tmp <= 0) {
|
||||
dev_dbg(chip->dev, "qcom,wf-fifo-data is not defined properly for effect %d\n",
|
||||
effect->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
effect->fifo = devm_kzalloc(chip->dev,
|
||||
sizeof(*effect->fifo), GFP_KERNEL);
|
||||
if (!effect->fifo)
|
||||
return -ENOMEM;
|
||||
|
||||
effect->fifo->samples = devm_kcalloc(chip->dev,
|
||||
tmp, sizeof(u8), GFP_KERNEL);
|
||||
if (!effect->fifo->samples)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = of_property_read_u8_array(node, "qcom,wf-fifo-data",
|
||||
effect->fifo->samples, tmp);
|
||||
if (rc < 0) {
|
||||
dev_err(chip->dev, "Read wf-fifo-data failed, rc=%d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
effect->fifo->num_s = tmp;
|
||||
effect->fifo->period_per_s = T_LRA;
|
||||
rc = of_property_read_u32(node, "qcom,wf-fifo-period", &tmp);
|
||||
if (rc < 0) {
|
||||
dev_err(chip->dev, "Get qcom,wf-fifo-period failed, rc=%d\n", rc);
|
||||
return rc;
|
||||
} else if (tmp > F_48KHZ) {
|
||||
dev_err(chip->dev, "FIFO playing period %d is not supported\n",
|
||||
tmp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
effect->fifo->period_per_s = tmp;
|
||||
effect->fifo->play_length_us =
|
||||
get_fifo_play_length_us(effect->fifo, config->t_lra_us);
|
||||
if (effect->fifo->play_length_us == -EINVAL) {
|
||||
dev_err(chip->dev, "get fifo play length failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
effect->src = FIFO;
|
||||
effect->fifo->preload = of_property_read_bool(node,
|
||||
"qcom,wf-fifo-preload");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int haptics_parse_effect_brake_data(struct haptics_chip *chip,
|
||||
struct device_node *node, struct haptics_effect *effect)
|
||||
{
|
||||
struct haptics_hw_config *config = &chip->config;
|
||||
int rc, tmp;
|
||||
|
||||
effect->brake = devm_kzalloc(chip->dev,
|
||||
sizeof(*effect->brake), GFP_KERNEL);
|
||||
if (!effect->brake)
|
||||
|
|
@ -3990,12 +4016,66 @@ static int haptics_parse_per_effect_dt(struct haptics_chip *chip,
|
|||
effect->brake->play_length_us =
|
||||
get_brake_play_length_us(effect->brake, config->t_lra_us);
|
||||
|
||||
if (config->is_erm)
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* LRA specific per-effect settings are parsed below */
|
||||
effect->auto_res_disable = of_property_read_bool(node,
|
||||
"qcom,wf-auto-res-disable");
|
||||
static int haptics_parse_per_effect_dt(struct haptics_chip *chip,
|
||||
struct device_node *node, struct haptics_effect *effect)
|
||||
{
|
||||
struct haptics_hw_config *config = &chip->config;
|
||||
int rc, tmp;
|
||||
|
||||
if (!effect)
|
||||
return -EINVAL;
|
||||
|
||||
rc = of_property_read_u32(node, "qcom,effect-id", &effect->id);
|
||||
if (rc < 0) {
|
||||
dev_err(chip->dev, "read qcom,effect-id failed, rc=%d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
effect->vmax_mv = config->vmax_mv;
|
||||
rc = of_property_read_u32(node, "qcom,wf-vmax-mv", &tmp);
|
||||
if (rc < 0)
|
||||
dev_dbg(chip->dev, "read qcom,wf-vmax-mv failed, rc=%d\n",
|
||||
rc);
|
||||
else
|
||||
effect->vmax_mv = tmp;
|
||||
|
||||
if (effect->vmax_mv > MAX_VMAX_MV) {
|
||||
dev_err(chip->dev, "qcom,wf-vmax-mv (%d) exceed the max value: %d\n",
|
||||
effect->vmax_mv, MAX_VMAX_MV);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = haptics_parse_effect_pattern_data(chip, node, effect);
|
||||
if (rc < 0) {
|
||||
dev_err(chip->dev, "parse effect PATTERN data failed, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = haptics_parse_effect_fifo_data(chip, node, effect);
|
||||
if (rc < 0) {
|
||||
dev_err(chip->dev, "parse effect FIFO data failed, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!effect->pattern && !effect->fifo) {
|
||||
dev_err(chip->dev, "no pattern specified for effect %d\n",
|
||||
effect->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = haptics_parse_effect_brake_data(chip, node, effect);
|
||||
if (rc < 0) {
|
||||
dev_err(chip->dev, "parse effect brake data failed, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!config->is_erm)
|
||||
effect->auto_res_disable = of_property_read_bool(node,
|
||||
"qcom,wf-auto-res-disable");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -4086,6 +4166,10 @@ static int haptics_parse_lra_dt(struct haptics_chip *chip)
|
|||
}
|
||||
}
|
||||
|
||||
if (chip->hw_type == HAP525_HV)
|
||||
config->measure_lra_impedance = of_property_read_bool(node,
|
||||
"qcom,rt-imp-detect");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -4478,25 +4562,164 @@ static int haptics_pbs_trigger_isc_config(struct haptics_chip *chip)
|
|||
}
|
||||
|
||||
#define MAX_SWEEP_STEPS 5
|
||||
#define MAX_IMPEDANCE_MOHM 40000
|
||||
#define MIN_ISC_MA 250
|
||||
#define MIN_DUTY_MILLI_PCT 0
|
||||
#define MAX_DUTY_MILLI_PCT 100000
|
||||
#define LRA_CONFIG_REGS 3
|
||||
static u32 get_lra_impedance_capable_max(struct haptics_chip *chip)
|
||||
{
|
||||
u32 mohms = MAX_IMPEDANCE_MOHM;
|
||||
u32 mohms;
|
||||
u32 max_vmax_mv, min_isc_ma;
|
||||
|
||||
if (chip->clamp_at_5v)
|
||||
mohms = MAX_IMPEDANCE_MOHM / 2;
|
||||
switch (chip->hw_type) {
|
||||
case HAP520:
|
||||
min_isc_ma = 250;
|
||||
if (chip->clamp_at_5v)
|
||||
max_vmax_mv = 5000;
|
||||
else
|
||||
max_vmax_mv = 10000;
|
||||
break;
|
||||
case HAP520_MV:
|
||||
max_vmax_mv = 5000;
|
||||
min_isc_ma = 140;
|
||||
break;
|
||||
case HAP525_HV:
|
||||
if (chip->clamp_at_5v) {
|
||||
max_vmax_mv = 5000;
|
||||
min_isc_ma = 125;
|
||||
} else {
|
||||
max_vmax_mv = 10000;
|
||||
min_isc_ma = 250;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
mohms = (max_vmax_mv * 1000) / min_isc_ma;
|
||||
if (is_haptics_external_powered(chip))
|
||||
mohms = (chip->hpwr_voltage_mv * 1000) / MIN_ISC_MA;
|
||||
mohms = (chip->hpwr_voltage_mv * 1000) / min_isc_ma;
|
||||
|
||||
dev_dbg(chip->dev, "LRA impedance capable max: %u mohms\n", mohms);
|
||||
return mohms;
|
||||
}
|
||||
|
||||
#define RT_IMPD_DET_VMAX_DEFAULT_MV 4500
|
||||
static int haptics_measure_realtime_lra_impedance(struct haptics_chip *chip)
|
||||
{
|
||||
int rc;
|
||||
u8 val, current_sel;
|
||||
u32 vmax_mv, nominal_ohm, current_ma, vmax_margin_mv;
|
||||
struct pattern_cfg pattern = {
|
||||
.samples = {
|
||||
{0xff, T_LRA, false},
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
},
|
||||
.play_rate_us = chip->config.t_lra_us + 2000, /* drive off resonance of the LRA */
|
||||
.play_length_us = chip->config.t_lra_us + 2000, /* drive it at least 1 cycle */
|
||||
.preload = false,
|
||||
};
|
||||
|
||||
/* calculate Vmax according to nominal resistance */
|
||||
vmax_mv = RT_IMPD_DET_VMAX_DEFAULT_MV;
|
||||
current_sel = chip->clamp_at_5v ? CURRENT_SEL_VAL_125MA : CURRENT_SEL_VAL_250MA;
|
||||
if (chip->hap_cfg_nvmem != NULL) {
|
||||
rc = nvmem_device_read(chip->hap_cfg_nvmem,
|
||||
HAP_LRA_NOMINAL_OHM_SDAM_OFFSET, 1, &val);
|
||||
if (!rc && val) {
|
||||
nominal_ohm = val;
|
||||
/*
|
||||
* use 250mA current_sel when nominal impedance is lower than 15 Ohms
|
||||
* and use 125mA detection when nominal impedance is higher than 40 Ohms
|
||||
*/
|
||||
if (nominal_ohm < 15)
|
||||
current_sel = CURRENT_SEL_VAL_250MA;
|
||||
else if (nominal_ohm > 40)
|
||||
current_sel = CURRENT_SEL_VAL_125MA;
|
||||
|
||||
/*
|
||||
* give 8 Ohms margin (1000mV / 125mA, or 2000mV / 250mA) for wider
|
||||
* detectability
|
||||
*/
|
||||
if (current_sel == CURRENT_SEL_VAL_125MA) {
|
||||
current_ma = 125;
|
||||
vmax_margin_mv = 1000;
|
||||
} else {
|
||||
current_ma = 250;
|
||||
vmax_margin_mv = 2000;
|
||||
}
|
||||
|
||||
vmax_mv = max(vmax_mv, nominal_ohm * current_ma + vmax_margin_mv);
|
||||
}
|
||||
}
|
||||
|
||||
dev_dbg(chip->dev, "Set %u mV Vmax for impedance detection\n", vmax_mv);
|
||||
rc = haptics_set_vmax_mv(chip, vmax_mv);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* set current for imp_det comparator and enable it */
|
||||
val = LRA_IMPEDANCE_MEAS_EN_BIT | current_sel;
|
||||
rc = haptics_masked_write(chip, chip->cfg_addr_base,
|
||||
HAP_CFG_RT_LRA_IMPD_MEAS_CFG_REG,
|
||||
LRA_IMPEDANCE_MEAS_EN_BIT |
|
||||
LRA_IMPEDANCE_MEAS_CURRENT_SEL_BIT, val);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* disconnect imp_det comparator to avoid it impact SC behavior */
|
||||
rc = haptics_masked_write(chip, chip->cfg_addr_base,
|
||||
HAP_CFG_ISC_CFG_REG, EN_IMP_DET_HAP525_HV_BIT, 0);
|
||||
if (rc < 0)
|
||||
goto restore;
|
||||
|
||||
/* play 1 drive cycle using PATTERN1 source */
|
||||
rc = haptics_set_pattern(chip, &pattern, PATTERN1);
|
||||
if (rc < 0)
|
||||
goto restore;
|
||||
|
||||
chip->play.pattern_src = PATTERN1;
|
||||
rc = haptics_enable_play(chip, true);
|
||||
if (rc < 0)
|
||||
goto restore;
|
||||
|
||||
usleep_range(pattern.play_length_us, pattern.play_length_us + 1);
|
||||
|
||||
rc = haptics_enable_play(chip, false);
|
||||
if (rc < 0)
|
||||
goto restore;
|
||||
|
||||
/* read the measured LRA impedance */
|
||||
rc = haptics_read(chip, chip->cfg_addr_base,
|
||||
HAP_CFG_REAL_TIME_LRA_IMPEDANCE_REG, &val, 1);
|
||||
if (rc < 0)
|
||||
goto restore;
|
||||
|
||||
chip->config.lra_measured_mohms = val * LRA_IMPEDANCE_MOHMS_LSB;
|
||||
dev_dbg(chip->dev, "measured LRA impedance: %u mohm",
|
||||
chip->config.lra_measured_mohms);
|
||||
/* store the detected LRA impedance into SDAM for future usage */
|
||||
if (chip->hap_cfg_nvmem != NULL) {
|
||||
rc = nvmem_device_write(chip->hap_cfg_nvmem, HAP_LRA_DETECTED_OHM_SDAM_OFFSET, 1,
|
||||
&chip->config.lra_measured_mohms);
|
||||
if (rc < 0)
|
||||
dev_err(chip->dev, "write measured impedance value into SDAM failed, rc=%d\n",
|
||||
rc);
|
||||
}
|
||||
restore:
|
||||
if (rc < 0)
|
||||
dev_err(chip->dev, "measure LRA impedance failed, rc=%d\n", rc);
|
||||
|
||||
return haptics_masked_write(chip, chip->cfg_addr_base,
|
||||
HAP_CFG_RT_LRA_IMPD_MEAS_CFG_REG,
|
||||
LRA_IMPEDANCE_MEAS_EN_BIT, 0);
|
||||
}
|
||||
|
||||
static int haptics_detect_lra_impedance(struct haptics_chip *chip)
|
||||
{
|
||||
int rc, i;
|
||||
|
|
@ -4506,7 +4729,7 @@ static int haptics_detect_lra_impedance(struct haptics_chip *chip)
|
|||
{ HAP_CFG_VMAX_HDRM_REG, 0x00 },
|
||||
};
|
||||
struct haptics_reg_info backup[LRA_CONFIG_REGS];
|
||||
u8 val;
|
||||
u8 val, cfg1, cfg2, reg1, reg2, mask1, mask2, val1, val2;
|
||||
u32 duty_milli_pct, low_milli_pct, high_milli_pct;
|
||||
u32 amplitude, lra_min_mohms, lra_max_mohms, capability_mohms;
|
||||
|
||||
|
|
@ -4519,10 +4742,61 @@ static int haptics_detect_lra_impedance(struct haptics_chip *chip)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/* Trigger PBS to config 250mA ISC setting */
|
||||
rc = haptics_pbs_trigger_isc_config(chip);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (chip->hw_type == HAP520) {
|
||||
/* Trigger PBS to config 250mA ISC setting */
|
||||
rc = haptics_pbs_trigger_isc_config(chip);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
} else {
|
||||
/* Config ISC_CFG settings for LRA impedance_detection */
|
||||
switch (chip->hw_type) {
|
||||
case HAP520_MV:
|
||||
reg1 = HAP_CFG_ISC_CFG_REG;
|
||||
mask1 = ILIM_CC_EN_BIT;
|
||||
val1 = ILIM_CC_EN_BIT;
|
||||
reg2 = HAP_CFG_ISC_CFG2_REG;
|
||||
mask2 = EN_SC_DET_P_HAP520_MV_BIT |
|
||||
EN_SC_DET_N_HAP520_MV_BIT |
|
||||
ISC_THRESH_HAP520_MV_MASK;
|
||||
val2 = EN_SC_DET_P_HAP520_MV_BIT|
|
||||
EN_SC_DET_N_HAP520_MV_BIT|
|
||||
ISC_THRESH_HAP520_MV_140MA;
|
||||
break;
|
||||
case HAP525_HV:
|
||||
reg1 = HAP_CFG_ISC_CFG_REG;
|
||||
mask1 = EN_SC_DET_P_HAP525_HV_BIT | EN_SC_DET_N_HAP525_HV_BIT |
|
||||
EN_IMP_DET_HAP525_HV_BIT | ILIM_PULSE_DENSITY_MASK;
|
||||
val1 = EN_IMP_DET_HAP525_HV_BIT |
|
||||
FIELD_PREP(ILIM_PULSE_DENSITY_MASK, ILIM_DENSITY_8_OVER_64_CYCLES);
|
||||
reg2 = HAP_CFG_RT_LRA_IMPD_MEAS_CFG_REG;
|
||||
mask2 = LRA_IMPEDANCE_MEAS_EN_BIT | LRA_IMPEDANCE_MEAS_CURRENT_SEL_BIT;
|
||||
val2 = chip->clamp_at_5v ? CURRENT_SEL_VAL_125MA : CURRENT_SEL_VAL_250MA;
|
||||
val2 |= LRA_IMPEDANCE_MEAS_EN_BIT;
|
||||
break;
|
||||
default:
|
||||
dev_err(chip->dev, "unsupported HW type: %d\n",
|
||||
chip->hw_type);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* save ISC_CFG default settings */
|
||||
rc = haptics_read(chip, chip->cfg_addr_base, reg1, &cfg1, 1);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = haptics_read(chip, chip->cfg_addr_base, reg2, &cfg2, 1);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* update ISC_CFG settings for the detection */
|
||||
rc = haptics_masked_write(chip, chip->cfg_addr_base, reg1, mask1, val1);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = haptics_masked_write(chip, chip->cfg_addr_base, reg2, mask2, val2);
|
||||
if (rc < 0)
|
||||
goto restore;
|
||||
}
|
||||
|
||||
/* Set square drive waveform, 10V Vmax, no HDRM */
|
||||
for (i = 0; i < LRA_CONFIG_REGS; i++) {
|
||||
|
|
@ -4599,10 +4873,21 @@ static int haptics_detect_lra_impedance(struct haptics_chip *chip)
|
|||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Trigger PBS to restore 1500mA ISC setting */
|
||||
rc = haptics_pbs_trigger_isc_config(chip);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (chip->hw_type == HAP520) {
|
||||
/* Trigger PBS to restore 1500mA ISC setting */
|
||||
rc = haptics_pbs_trigger_isc_config(chip);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
} else {
|
||||
/* restore ISC_CFG settings to default */
|
||||
rc = haptics_write(chip, chip->cfg_addr_base, reg1, &cfg1, 1);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = haptics_write(chip, chip->cfg_addr_base, reg2, &cfg2, 1);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Restore driver waveform, Vmax, HDRM settings */
|
||||
for (i = 0; i < LRA_CONFIG_REGS; i++) {
|
||||
|
|
@ -4736,7 +5021,10 @@ static int haptics_start_lra_calibrate(struct haptics_chip *chip)
|
|||
|
||||
/* Sleep at least 4ms to stabilize the LRA from frequency detection */
|
||||
usleep_range(4000, 5000);
|
||||
rc = haptics_detect_lra_impedance(chip);
|
||||
if (chip->config.measure_lra_impedance)
|
||||
rc = haptics_measure_realtime_lra_impedance(chip);
|
||||
else
|
||||
rc = haptics_detect_lra_impedance(chip);
|
||||
if (rc < 0) {
|
||||
dev_err(chip->dev, "Detect LRA impedance failed, rc=%d\n", rc);
|
||||
goto unlock;
|
||||
|
|
@ -4790,6 +5078,10 @@ static ssize_t lra_impedance_show(struct class *c,
|
|||
struct haptics_chip *chip = container_of(c,
|
||||
struct haptics_chip, hap_class);
|
||||
|
||||
if (chip->config.measure_lra_impedance)
|
||||
return scnprintf(buf, PAGE_SIZE, "measured %u mohms\n",
|
||||
chip->config.lra_measured_mohms);
|
||||
|
||||
if (chip->config.lra_min_mohms == 0 && chip->config.lra_max_mohms == 0)
|
||||
return -EINVAL;
|
||||
else if (chip->config.lra_min_mohms == 0)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user