input: misc: qcom-hv-haptics: Import changes from yudi-t-oss

Change-Id: Idaaf0e677f9212d32254f92d2d8eb9ce655ddb27
Signed-off-by: Jens Reidel <adrian@travitia.xyz>
This commit is contained in:
Jens Reidel 2024-04-12 19:13:00 +02:00
parent 0b7362e433
commit eea21f2798
No known key found for this signature in database
GPG Key ID: 23C1E5F512C12303
2 changed files with 244 additions and 13 deletions

View File

@ -31,3 +31,31 @@ obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o
obj-$(CONFIG_RMI4_CORE) += rmi4/
obj-$(CONFIG_INPUT_FINGERPRINT) += fingerprint/
obj-$(CONFIG_STMVL53L5) += stmvl53l5/
ifeq ($(TARGET_PRODUCT), diting)
KBUILD_CPPFLAGS += -DCONFIG_TARGET_PRODUCT_DITING
endif
ifeq ($(TARGET_PRODUCT), mayfly)
KBUILD_CPPFLAGS += -DCONFIG_TARGET_PRODUCT_MAYFLY
KBUILD_CPPFLAGS += -DQCOM_HAPTIC_F0_PROTECT
endif
ifeq ($(TARGET_PRODUCT), zizhan)
KBUILD_CPPFLAGS += -DCONFIG_TARGET_PRODUCT_ZIZHAN
KBUILD_CPPFLAGS += -DQCOM_HAPTIC_F0_PROTECT
endif
ifeq ($(TARGET_PRODUCT), mondrian)
KBUILD_CPPFLAGS += -DCONFIG_TARGET_PRODUCT_MONDRIAN
endif
ifeq ($(TARGET_PRODUCT), marble)
KBUILD_CPPFLAGS += -DCONFIG_TARGET_PRODUCT_MARBLE
KBUILD_CPPFLAGS += -DQCOM_HAPTIC_F0_PROTECT
endif
ifeq ($(TARGET_PRODUCT), yudi)
KBUILD_CPPFLAGS += -DCONFIG_TARGET_PRODUCT_YUDI
KBUILD_CPPFLAGS += -DQCOM_HAPTIC_F0_PROTECT
endif

View File

@ -27,6 +27,8 @@
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/qpnp/qpnp-pbs.h>
#include <linux/power_supply.h>
#include <linux/mmhardware_sysfs.h>
#include <linux/soc/qcom/battery_charger.h>
@ -40,6 +42,7 @@
#define HAP_CFG_V3 0x3
#define HAP_CFG_V4 0x4
#define DEBUG
#define HAP_CFG_STATUS_DATA_MSB_REG 0x09
/* STATUS_DATA_MSB definitions while MOD_STATUS_SEL is 0 */
#define AUTO_RES_CAL_DONE_BIT BIT(5)
@ -141,6 +144,10 @@
#define HAP_CFG_DRV_DUTY_CFG_REG 0x60
#define ADT_DRV_DUTY_EN_BIT BIT(7)
#define DRV_DUTY_MASK GENMASK(5, 3)
#define DRV_DUTY_62P5_PERCENT 0x2
#define DRV_DUTY_SHIFT 3
#define HAP_CFG_ADT_DRV_DUTY_CFG_REG 0x61
#define HAP_CFG_ZX_WIND_CFG_REG 0x62
@ -149,6 +156,7 @@
#define AUTORES_EN_DLY_MASK GENMASK(5, 2)
#define AUTORES_EN_DLY(cycles) ((cycles) * 2)
#define AUTORES_EN_DLY_6_CYCLES AUTORES_EN_DLY(6)
#define AUTORES_EN_DLY_7_CYCLES AUTORES_EN_DLY(7)
#define AUTORES_EN_DLY_SHIFT 2
#define AUTORES_ERR_WINDOW_MASK GENMASK(1, 0)
#define AUTORES_ERR_WINDOW_12P5_PERCENT 0x0
@ -335,6 +343,11 @@
#define is_between(val, min, max) \
(((min) <= (max)) && ((min) <= (val)) && ((val) <= (max)))
#if IS_ENABLED(CONFIG_MMHARDWARE_DETECTION)
static DEFINE_MUTEX(haptic_lock);
static int dev_cnt = 0;
#endif
enum hap_status_sel {
CAL_TLRA_CL_STS = 0x00,
T_WIND_STS,
@ -565,6 +578,9 @@ struct haptics_hw_config {
enum drv_sig_shape drv_wf;
bool is_erm;
bool measure_lra_impedance;
#if defined(CONFIG_TARGET_PRODUCT_YUDI)
bool lra_calibrated;
#endif
};
struct custom_fifo_data {
@ -592,6 +608,11 @@ struct haptics_chip {
struct class hap_class;
struct regulator *hpwr_vreg;
struct hrtimer hbst_off_timer;
struct hrtimer dph_off_timer; /*DIRECT_PLAY turning off timer*/
#if defined(CONFIG_TARGET_PRODUCT_MAYFLY) || defined(CONFIG_TARGET_PRODUCT_YUDI)
struct power_supply *wls_psy;
#endif
bool hboost_quick_off;
struct notifier_block hboost_nb;
int fifo_empty_irq;
u32 hpwr_voltage_mv;
@ -1050,6 +1071,13 @@ static int haptics_get_closeloop_lra_period(
u64 tmp;
int rc;
#ifdef QCOM_HAPTIC_F0_PROTECT
//protect low rate of xbl f0 abnormal for L18 only
int f0_mix, f0_max, f0_default, f0_cnt;
int rc1, rc2, rc3, rc4;
struct device_node *node = chip->dev->of_node;
#endif
/* read RC_CLK_CAL enabling mode */
rc = haptics_read(chip, chip->cfg_addr_base,
HAP_CFG_CAL_EN_REG, val, 1);
@ -1089,9 +1117,13 @@ static int haptics_get_closeloop_lra_period(
tlra_cl_err_sts =
((val[0] & TLRA_CL_ERR_MSB_MASK) << 8) | val[1];
dev_dbg(chip->dev, "rc_clk_cal = %u, auto_res_done = %d\n",
dev_info(chip->dev, "rc_clk_cal = %u, auto_res_done = %d\n",
rc_clk_cal, auto_res_done);
#if defined(CONFIG_TARGET_PRODUCT_YUDI)
chip->config.lra_calibrated = auto_res_done;
#endif
if (rc_clk_cal == CAL_RC_CLK_DISABLED_VAL && !auto_res_done) {
/* TLRA_CL_ERR(us) = TLRA_CL_ERR_STS * 1.667 us */
tmp = tlra_cl_err_sts * TLRA_AUTO_RES_ERR_NO_CAL_STEP_PSEC;
@ -1177,12 +1209,46 @@ static int haptics_get_closeloop_lra_period(
tmp = div_u64(tmp, last_good_tlra_cl_sts);
tmp = div_u64(tmp, 293);
config->rc_clk_cal_count = div_u64(tmp, config->t_lra_us);
} else {
dev_err(chip->dev, "Can't get close-loop LRA period in rc_clk_cal mode %u\n",
rc_clk_cal);
return -EINVAL;
}
#ifdef QCOM_HAPTIC_F0_PROTECT
/* protect low rate of xbl f0 abnormal */
if(in_boot){
u32 xbl_f0 = USEC_PER_SEC / config->cl_t_lra_us;
dev_info(chip->dev, "xbl f0 =%d \n", xbl_f0);
rc1 = of_property_read_u32(node, "qcom,lra-f0-min", &f0_mix);
if (rc1 < 0) {
dev_err(chip->dev, "lra-f0-min failed, rc=%d\n", rc);
}
rc2 = of_property_read_u32(node, "qcom,lra-f0-max", &f0_max);
if (rc2 < 0) {
dev_err(chip->dev, "lra-f0-max failed, rc=%d\n", rc);
}
rc3 = of_property_read_u32(node, "qcom,lra-f0-default", &f0_default);
if (rc3 < 0) {
dev_err(chip->dev, "lra-f0-default failed, rc=%d\n", rc);
}
rc4 = of_property_read_u32(node, "qcom,lra-f0-cal-count", &f0_cnt);
if (rc4 < 0) {
dev_err(chip->dev, "lra-f0-cal-count failed, rc=%d\n", rc);
}
if (rc1 >= 0 && rc2 >= 0 && rc3 >= 0 && rc4 >= 0) {
if (xbl_f0 > f0_max || xbl_f0 < f0_mix) {
dev_info(chip->dev, "xbl f0 abnormal: %d ~ 0x%x use default: %d ~ 0x%x f0:%d - %d after boot\n",xbl_f0, config->rc_clk_cal_count, f0_default, f0_cnt, f0_mix, f0_max);
config->cl_t_lra_us = USEC_PER_SEC / f0_default;
config->rc_clk_cal_count = f0_cnt;
}
} else {
dev_err(chip->dev, "lra-f0: default min max count must set together in dtsi\n");
}
}
#endif
dev_dbg(chip->dev, "OL_TLRA %u us, CL_TLRA %u us, RC_CLK_CAL_COUNT %#x\n",
chip->config.t_lra_us, chip->config.cl_t_lra_us,
chip->config.rc_clk_cal_count);
@ -1609,8 +1675,6 @@ static int haptics_enable_play(struct haptics_chip *chip, bool en)
if (chip->hw_type == HAP525_HV && play->pattern_src == PATTERN_MEM)
val |= FIELD_PREP(PATX_MEM_SEL_MASK, play->effect->pat_sel);
if (play->brake && !play->brake->disabled)
val |= BRAKE_EN_BIT;
if (en)
val |= PLAY_EN_BIT;
@ -1893,11 +1957,39 @@ static int haptics_get_fifo_fill_status(struct haptics_chip *chip, u32 *fill)
return 0;
}
#if defined(CONFIG_TARGET_PRODUCT_MAYFLY) || defined(CONFIG_TARGET_PRODUCT_YUDI)
static bool get_wls_backcharge_enable(struct haptics_chip *chip) {
int rc;
union power_supply_propval val;
if(!chip->wls_psy) {
chip->wls_psy = power_supply_get_by_name("wireless");
}
if (chip->wls_psy) {
rc = power_supply_get_property(chip->wls_psy,
POWER_SUPPLY_PROP_PRESENT,
&val);
if (rc < 0) {
dev_err(chip->dev, "Couldn't get POWER_SUPPLY_PROP_PRESENT, rc=%d\n",
rc);
return false;
}
return val.intval == 1;
}
dev_err(chip->dev, "Couldn't get wls_backcharge_enable, wsl_psy is null!");
return false;
}
#endif
static int haptics_get_available_fifo_memory(struct haptics_chip *chip)
{
int rc;
u32 fill, available;
#if defined(CONFIG_TARGET_PRODUCT_MAYFLY) || defined(CONFIG_TARGET_PRODUCT_YUDI)
if (get_wls_backcharge_enable(chip)) {
dev_dbg(chip->dev, "wireless backcharge enabled, skip haptics!");
return -EBUSY;
}
#endif
rc = haptics_get_fifo_fill_status(chip, &fill);
if (rc < 0)
return rc;
@ -2060,7 +2152,7 @@ static int haptics_set_fifo(struct haptics_chip *chip, struct fifo_cfg *fifo)
return 0;
}
static int haptics_load_constant_effect(struct haptics_chip *chip, u8 amplitude)
static int haptics_load_constant_effect(struct haptics_chip *chip, u8 amplitude, u32 length_us)
{
struct haptics_play_info *play = &chip->play;
u32 hdrm_mv, vmax_mv = chip->config.vmax_mv;
@ -2076,6 +2168,10 @@ static int haptics_load_constant_effect(struct haptics_chip *chip, u8 amplitude)
/* No effect data when playing constant waveform */
play->effect = NULL;
/*set play time*/
play->length_us = length_us;
dev_dbg(chip->dev, "play->length_us is %u us", play->length_us);
/* Fix Vmax to (hpwr_vreg_mv - hdrm_mv) in non-HBOOST regulator case */
if (is_haptics_external_powered(chip)) {
rc = haptics_get_vmax_headroom_mv(chip, &hdrm_mv);
@ -2103,7 +2199,7 @@ static int haptics_load_constant_effect(struct haptics_chip *chip, u8 amplitude)
goto unlock;
/* Always enable LRA auto resonance for DIRECT_PLAY */
rc = haptics_enable_autores(chip, !chip->config.is_erm);
rc = haptics_enable_autores(chip, false);
if (rc < 0)
goto unlock;
@ -2212,7 +2308,19 @@ static int haptics_init_custom_effect(struct haptics_chip *chip)
chip->custom_effect->pattern = NULL;
chip->custom_effect->brake = NULL;
chip->custom_effect->id = UINT_MAX;
chip->custom_effect->vmax_mv = chip->config.vmax_mv;
#ifdef CONFIG_TARGET_PRODUCT_DITING
chip->custom_effect->vmax_mv = 9000;
#elif defined(CONFIG_TARGET_PRODUCT_MONDRIAN)
chip->custom_effect->vmax_mv = 9000;
#elif defined(CONFIG_TARGET_PRODUCT_MAYFLY)
chip->custom_effect->vmax_mv = 9100;
#elif defined(CONFIG_TARGET_PRODUCT_MARBLE)
chip->custom_effect->vmax_mv = 9100;
#elif defined(CONFIG_TARGET_PRODUCT_YUDI)
chip->custom_effect->vmax_mv = 5000;
#else
chip->custom_effect->vmax_mv = 4200; //chip->config.vmax_mv
#endif
chip->custom_effect->t_lra_us = chip->config.t_lra_us;
chip->custom_effect->src = FIFO;
chip->custom_effect->auto_res_disable = true;
@ -2328,7 +2436,8 @@ static int haptics_load_custom_effect(struct haptics_chip *chip,
play->effect = chip->custom_effect;
play->brake = NULL;
play->vmax_mv = (magnitude * chip->custom_effect->vmax_mv) / 0x7fff;
dev_dbg(chip->dev, "set magnitude on custom effect, rc=%d\n", magnitude);
play->vmax_mv = (magnitude * chip->custom_effect->vmax_mv) / 0x7fff;
rc = haptics_set_vmax_mv(chip, play->vmax_mv);
if (rc < 0)
goto cleanup;
@ -2526,7 +2635,17 @@ static int haptics_upload_effect(struct input_dev *dev,
s16 level;
u8 amplitude;
int rc = 0;
#if defined(CONFIG_TARGET_PRODUCT_MAYFLY) || defined(CONFIG_TARGET_PRODUCT_YUDI)
if(effect->type == FF_DAMPER){
chip->hboost_quick_off = true;
dev_info(chip->dev, "set hboost quick off!");
return 0;
}
if (get_wls_backcharge_enable(chip)) {
dev_info(chip->dev, "wireless backcharge enabled, skip haptics!");
return 0;
}
#endif
switch (effect->type) {
case FF_CONSTANT:
length_us = effect->replay.length * USEC_PER_MSEC;
@ -2536,7 +2655,7 @@ static int haptics_upload_effect(struct input_dev *dev,
amplitude = tmp / 0x7fff;
dev_dbg(chip->dev, "upload constant effect, length = %dus, amplitude = %#x\n",
length_us, amplitude);
haptics_load_constant_effect(chip, amplitude);
haptics_load_constant_effect(chip, amplitude, length_us);
if (rc < 0) {
dev_err(chip->dev, "set direct play failed, rc=%d\n",
rc);
@ -2610,12 +2729,23 @@ static int haptics_playback(struct input_dev *dev, int effect_id, int val)
struct haptics_chip *chip = input_get_drvdata(dev);
struct haptics_play_info *play = &chip->play;
int rc;
#if defined(CONFIG_TARGET_PRODUCT_MAYFLY) || defined(CONFIG_TARGET_PRODUCT_YUDI)
if (get_wls_backcharge_enable(chip)) {
dev_dbg(chip->dev, "wireless backcharge enabled, skip haptics!");
val = 0;
}
#endif
dev_dbg(chip->dev, "playback val = %d\n", val);
if (!!val) {
rc = haptics_enable_play(chip, true);
if (rc < 0)
return rc;
if (play->pattern_src == DIRECT_PLAY) {
u64 length_ns = play->length_us * NSEC_PER_USEC;
hrtimer_start(&chip->dph_off_timer,
ns_to_ktime(length_ns),
HRTIMER_MODE_REL);
}
} else {
if (play->pattern_src == FIFO &&
atomic_read(&play->fifo_status.is_busy)) {
@ -2635,6 +2765,16 @@ static int haptics_erase(struct input_dev *dev, int effect_id)
struct haptics_play_info *play = &chip->play;
int rc;
dev_info(chip->dev, "haptics_erase\n");
if(chip->hboost_quick_off){
rc = haptics_boost_vreg_enable(chip, false);
if(rc < 0)
dev_err(chip->dev, "hboost quick off failed, rc=%d\n", rc);
else
dev_info(chip->dev, "hboost quick off\n");
chip->hboost_quick_off = false;
return 0;
}
mutex_lock(&play->lock);
if ((play->pattern_src == FIFO) &&
atomic_read(&play->fifo_status.is_busy)) {
@ -2642,7 +2782,11 @@ static int haptics_erase(struct input_dev *dev, int effect_id)
dev_dbg(chip->dev, "cancelling FIFO playing\n");
atomic_set(&play->fifo_status.cancelled, 1);
}
#if defined(CONFIG_TARGET_PRODUCT_MAYFLY) || defined(CONFIG_TARGET_PRODUCT_DITING) || defined(CONFIG_TARGET_PRODUCT_ZIZHAN) || defined(CONFIG_TARGET_PRODUCT_MONDRIAN) || defined(CONFIG_TARGET_PRODUCT_YUDI)
#define FIFO_PLAY_STOP_DELAY 9
msleep(FIFO_PLAY_STOP_DELAY);
dev_info(chip->dev, "fifo play stop delay %d ms\n", FIFO_PLAY_STOP_DELAY);
#endif
rc = haptics_stop_fifo_play(chip);
if (rc < 0) {
dev_err(chip->dev, "stop FIFO playing failed, rc=%d\n",
@ -3343,6 +3487,7 @@ static ssize_t pattern_s_dbgfs_write(struct file *fp,
rc = -EINVAL;
goto exit;
}
tmp[i++] = val;
}
@ -5099,13 +5244,22 @@ static int haptics_detect_lra_frequency(struct haptics_chip *chip)
rc = haptics_masked_write(chip, chip->cfg_addr_base,
HAP_CFG_AUTORES_CFG_REG, AUTORES_EN_BIT |
AUTORES_EN_DLY_MASK | AUTORES_ERR_WINDOW_MASK,
#if defined(CONFIG_TARGET_PRODUCT_MONDRIAN) || defined(CONFIG_TARGET_PRODUCT_YUDI)
AUTORES_EN_DLY_7_CYCLES << AUTORES_EN_DLY_SHIFT
#else
AUTORES_EN_DLY_6_CYCLES << AUTORES_EN_DLY_SHIFT
#endif
| AUTORES_ERR_WINDOW_50_PERCENT | AUTORES_EN_BIT);
if (rc < 0)
return rc;
rc = haptics_masked_write(chip, chip->cfg_addr_base,
#if defined(CONFIG_TARGET_PRODUCT_MONDRIAN) || defined(CONFIG_TARGET_PRODUCT_YUDI)
HAP_CFG_DRV_DUTY_CFG_REG, ADT_DRV_DUTY_EN_BIT |
DRV_DUTY_MASK, DRV_DUTY_62P5_PERCENT << DRV_DUTY_SHIFT);
#else
HAP_CFG_DRV_DUTY_CFG_REG, ADT_DRV_DUTY_EN_BIT, 0);
#endif
if (rc < 0)
goto restore;
@ -5249,7 +5403,7 @@ static ssize_t lra_frequency_hz_show(struct class *c,
if (chip->config.cl_t_lra_us == 0)
return -EINVAL;
cl_f_lra = USEC_PER_SEC / chip->config.cl_t_lra_us;
cl_f_lra = USEC_PER_SEC * 10 / chip->config.cl_t_lra_us;
return scnprintf(buf, PAGE_SIZE, "%d Hz\n", cl_f_lra);
}
static CLASS_ATTR_RO(lra_frequency_hz);
@ -5277,6 +5431,17 @@ static ssize_t lra_impedance_show(struct class *c,
}
static CLASS_ATTR_RO(lra_impedance);
#if defined(CONFIG_TARGET_PRODUCT_YUDI)
static ssize_t lra_calibration_check_show(struct class *c,
struct class_attribute *attr, char *buf)
{
struct haptics_chip *chip = container_of(c,
struct haptics_chip, hap_class);
return scnprintf(buf, PAGE_SIZE, "%d\n", chip->config.lra_calibrated);
}
static CLASS_ATTR_RO(lra_calibration_check);
#endif
static ssize_t primitive_duration_show(struct class *c,
struct class_attribute *attr, char *buf)
{
@ -5319,6 +5484,9 @@ static struct attribute *hap_class_attrs[] = {
&class_attr_lra_frequency_hz.attr,
&class_attr_lra_impedance.attr,
&class_attr_primitive_duration.attr,
#if defined(CONFIG_TARGET_PRODUCT_YUDI)
&class_attr_lra_calibration_check.attr,
#endif
NULL,
};
ATTRIBUTE_GROUPS(hap_class);
@ -5338,6 +5506,19 @@ static enum hrtimer_restart haptics_disable_hbst_timer(struct hrtimer *timer)
return HRTIMER_NORESTART;
}
static enum hrtimer_restart haptics_disable_dph_timer(struct hrtimer *timer)
{
struct haptics_chip *chip = container_of(timer,
struct haptics_chip, dph_off_timer);
int rc;
rc = haptics_enable_play(chip, false);
if (rc < 0)
dev_err(chip->dev, "disable haptics play failed, rc =%d\n", rc);
else
dev_dbg(chip->dev, "disable direct play haptics with timer\n");
return HRTIMER_NORESTART;
}
static bool is_swr_supported(struct haptics_chip *chip)
{
/* HAP520_MV does not support soundwire */
@ -5439,6 +5620,8 @@ static int haptics_probe(struct platform_device *pdev)
chip->fifo_empty_irq_en = false;
hrtimer_init(&chip->hbst_off_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
chip->hbst_off_timer.function = haptics_disable_hbst_timer;
hrtimer_init(&chip->dph_off_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
chip->dph_off_timer.function = haptics_disable_dph_timer;
atomic_set(&chip->play.fifo_status.is_busy, 0);
atomic_set(&chip->play.fifo_status.written_done, 0);
@ -5452,6 +5635,7 @@ static int haptics_probe(struct platform_device *pdev)
if ((chip->effects_count != 0) || (chip->primitives_count != 0)) {
input_set_capability(input_dev, EV_FF, FF_PERIODIC);
input_set_capability(input_dev, EV_FF, FF_CUSTOM);
input_set_capability(input_dev, EV_FF, FF_DAMPER);
}
if (chip->effects_count + chip->primitives_count > MAX_EFFECT_COUNT)
@ -5479,6 +5663,23 @@ static int haptics_probe(struct platform_device *pdev)
}
dev_set_drvdata(chip->dev, chip);
#if IS_ENABLED(CONFIG_MMHARDWARE_DETECTION)
mutex_lock(&haptic_lock);
dev_cnt++;
mutex_unlock(&haptic_lock);
dev_err(chip->dev, "%s: dev_cnt %d \n", __func__, dev_cnt);
switch (dev_cnt) {
case 1:
register_kobj_under_mmsysfs(MM_HW_HAPTIC_1, "haptic1");
break;
case 2:
register_kobj_under_mmsysfs(MM_HW_HAPTIC_2, "haptic2");
break;
default:
break;
}
#endif
chip->hap_class.name = "qcom-haptics";
chip->hap_class.class_groups = hap_class_groups;
rc = class_register(&chip->hap_class);
@ -5596,6 +5797,8 @@ static int haptics_suspend_config(struct device *dev)
if (rc < 0)
return rc;
hrtimer_cancel(&chip->dph_off_timer);
return haptics_module_enable(chip, false);
}