diff --git a/drivers/input/misc/qcom-hv-haptics.c b/drivers/input/misc/qcom-hv-haptics.c index f1ca4a207eef..c73c25c35cc6 100644 --- a/drivers/input/misc/qcom-hv-haptics.c +++ b/drivers/input/misc/qcom-hv-haptics.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -578,6 +579,7 @@ struct haptics_chip { struct input_dev *input_dev; struct haptics_hw_config config; struct haptics_effect *effects; + struct haptics_effect *primitives; struct haptics_effect *custom_effect; struct haptics_play_info play; struct haptics_mmap mmap; @@ -593,11 +595,13 @@ struct haptics_chip { int fifo_empty_irq; u32 hpwr_voltage_mv; u32 effects_count; + u32 primitives_count; u32 cfg_addr_base; u32 ptn_addr_base; u32 hbst_addr_base; u32 clamped_vmax_mv; u32 wa_flags; + u32 primitive_duration; u8 cfg_revision; u8 ptn_revision; u8 hpwr_intf_ctl; @@ -733,7 +737,8 @@ static int haptics_masked_write(struct haptics_chip *chip, return rc; } -static void __dump_effects(struct haptics_chip *chip) +static void __dump_effects(struct haptics_chip *chip, + struct haptics_effect *effects, int effects_count) { struct haptics_effect *effect; struct pattern_s *sample; @@ -741,8 +746,8 @@ static void __dump_effects(struct haptics_chip *chip) u32 size, pos; int i, j; - for (i = 0; i < chip->effects_count; i++) { - effect = &chip->effects[i]; + for (i = 0; i < effects_count; i++) { + effect = &effects[i]; if (!effect) return; @@ -1042,7 +1047,7 @@ static int haptics_get_closeloop_lra_period( rc_clk_cal = ((val[0] & CAL_RC_CLK_MASK) >> CAL_RC_CLK_SHIFT); /* read auto resonance calibration result */ - if (in_boot && (chip->hw_type == HAP520)) { + if (in_boot && ((chip->hw_type == HAP520) || (chip->hw_type == HAP520_MV))) { if (chip->hap_cfg_nvmem == NULL) { dev_dbg(chip->dev, "nvmem device for hap_cfg is not defined\n"); return -EINVAL; @@ -1535,6 +1540,40 @@ static int haptics_open_loop_drive_config(struct haptics_chip *chip, bool en) return 0; } +static int haptics_module_enable(struct haptics_chip *chip, bool enable) +{ + u8 val; + int rc; + + val = enable ? HAPTICS_EN_BIT : 0; + rc = haptics_write(chip, chip->cfg_addr_base, + HAP_CFG_EN_CTL_REG, &val, 1); + if (rc < 0) + return rc; + + dev_dbg(chip->dev, "haptics module %s\n", + enable ? "enabled" : "disabled"); + return 0; +} + +static int haptics_toggle_module_enable(struct haptics_chip *chip) +{ + int rc; + + /* + * Updating HAPTICS_EN would vote hBoost enable status. Add 100us + * delay before updating HAPTICS_EN for hBoost to have enough time + * to handle its power transition. + */ + usleep_range(100, 101); + rc = haptics_module_enable(chip, false); + if (rc < 0) + return rc; + + usleep_range(100, 101); + return haptics_module_enable(chip, true); +} + #define BOOST_VREG_OFF_DELAY_SECONDS 2 static int haptics_enable_play(struct haptics_chip *chip, bool en) { @@ -1933,40 +1972,6 @@ static void haptics_fifo_empty_irq_config(struct haptics_chip *chip, } } -static int haptics_module_enable(struct haptics_chip *chip, bool enable) -{ - u8 val; - int rc; - - val = enable ? HAPTICS_EN_BIT : 0; - rc = haptics_write(chip, chip->cfg_addr_base, - HAP_CFG_EN_CTL_REG, &val, 1); - if (rc < 0) - return rc; - - dev_dbg(chip->dev, "haptics module %s\n", - enable ? "enabled" : "disabled"); - return 0; -} - -static int haptics_toggle_module_enable(struct haptics_chip *chip) -{ - int rc; - - /* - * Updating HAPTICS_EN would vote hBoost enable status. Add 100us - * delay before updating HAPTICS_EN for hBoost to have enough time - * to handle its power transition. - */ - usleep_range(100, 101); - rc = haptics_module_enable(chip, false); - if (rc < 0) - return rc; - - usleep_range(100, 101); - return haptics_module_enable(chip, true); -} - static int haptics_set_fifo(struct haptics_chip *chip, struct fifo_cfg *fifo) { struct fifo_play_status *status = &chip->play.fifo_status; @@ -2340,13 +2345,12 @@ static int haptics_load_custom_effect(struct haptics_chip *chip, return rc; } -static u32 get_play_length_us(struct haptics_play_info *play) +static u32 get_play_length_effect_us(struct haptics_effect *effect) { - struct haptics_effect *effect = play->effect; u32 length_us = 0; - if (play->brake) - length_us = play->brake->play_length_us; + if (effect->brake) + length_us = effect->brake->play_length_us; if ((effect->src == PATTERN1 || effect->src == PATTERN2) && effect->pattern) @@ -2357,29 +2361,58 @@ static u32 get_play_length_us(struct haptics_play_info *play) return length_us; } +static inline u32 get_play_length_us(struct haptics_play_info *play) +{ + return get_play_length_effect_us(play->effect); +} + +#define PRIMITIVE_EFFECT_ID_BIT BIT(15) +#define PRIMITIVE_EFFECT_ID_MASK GENMASK(14, 0) static int haptics_load_periodic_effect(struct haptics_chip *chip, s16 __user *data, u32 length, s16 magnitude) { struct haptics_play_info *play = &chip->play; s16 custom_data[CUSTOM_DATA_LEN] = { 0 }; + struct haptics_effect *effects = NULL; + s16 custom_id = 0; + int effects_count = 0; int rc, i; - - if (chip->effects_count == 0) - return -EINVAL; + bool primitive; if (copy_from_user(custom_data, data, sizeof(custom_data))) return -EFAULT; - for (i = 0; i < chip->effects_count; i++) - if (chip->effects[i].id == custom_data[CUSTOM_DATA_EFFECT_IDX]) + primitive = !!(custom_data[CUSTOM_DATA_EFFECT_IDX] & PRIMITIVE_EFFECT_ID_BIT); + + if (primitive) { + if (chip->primitives_count == 0) + return -EINVAL; + + custom_id = custom_data[CUSTOM_DATA_EFFECT_IDX] & PRIMITIVE_EFFECT_ID_MASK; + effects = chip->primitives; + effects_count = chip->primitives_count; + } else { + if (chip->effects_count == 0) + return -EINVAL; + + custom_id = custom_data[CUSTOM_DATA_EFFECT_IDX]; + effects = chip->effects; + effects_count = chip->effects_count; + } + + for (i = 0; i < effects_count; i++) + if (effects[i].id == custom_id) break; - if (i == chip->effects_count) { + if (i == effects_count) { dev_err(chip->dev, "effect%d is not supported!\n", custom_data[CUSTOM_DATA_EFFECT_IDX]); return -EINVAL; } + dev_dbg(chip->dev, "upload %s effect %d, vmax=%d\n", primitive ? "primitive" : "predefined", + effects[i].id, play->vmax_mv); + mutex_lock(&chip->play.lock); if (chip->play.in_calibration) { dev_err(chip->dev, "calibration in progress, ignore playing predefined effect\n"); @@ -2387,12 +2420,11 @@ static int haptics_load_periodic_effect(struct haptics_chip *chip, goto unlock; } - play->vmax_mv = (magnitude * chip->effects[i].vmax_mv) / 0x7fff; - dev_dbg(chip->dev, "upload effect %d, vmax_mv=%d\n", chip->effects[i].id, play->vmax_mv); - rc = haptics_load_predefined_effect(chip, &chip->effects[i]); + play->vmax_mv = (magnitude * effects[i].vmax_mv) / 0x7fff; + rc = haptics_load_predefined_effect(chip, &effects[i]); if (rc < 0) { dev_err(chip->dev, "Play predefined effect%d failed, rc=%d\n", - chip->effects[i].id, rc); + effects[i].id, rc); goto unlock; } mutex_unlock(&chip->play.lock); @@ -3803,12 +3835,37 @@ static int haptics_add_effects_debugfs(struct haptics_effect *effect, return 0; } -#define EFFECT_NAME_SIZE 12 +#define EFFECT_NAME_SIZE 15 +static int haptics_add_debugfs(struct dentry *hap_dir, struct haptics_effect *effects, + int count, char *effect_name) +{ + struct dentry *effect_dir; + char str[EFFECT_NAME_SIZE] = {0}; + int rc = 0; + int i = 0; + + for (; i < count; i++) { + scnprintf(str, ARRAY_SIZE(str), "%s%d", effect_name, effects[i].id); + effect_dir = debugfs_create_dir(str, hap_dir); + if (IS_ERR(effect_dir)) { + rc = PTR_ERR(effect_dir); + pr_err("create %s debugfs directory failed, rc=%d\n", str, rc); + return rc; + } + rc = haptics_add_effects_debugfs(&effects[i], effect_dir); + if (rc < 0) { + pr_err("create debugfs nodes for %s failed, rc=%d\n", str, rc); + return rc; + } + } + + return rc; +} + static int haptics_create_debugfs(struct haptics_chip *chip) { - struct dentry *hap_dir, *effect_dir, *file; - char str[EFFECT_NAME_SIZE] = {0}; - int rc, i; + struct dentry *hap_dir, *file; + int rc = 0; hap_dir = debugfs_create_dir("haptics", NULL); if (IS_ERR(hap_dir)) { @@ -3818,24 +3875,13 @@ static int haptics_create_debugfs(struct haptics_chip *chip) return rc; } - for (i = 0; i < chip->effects_count; i++) { - scnprintf(str, ARRAY_SIZE(str), "effect%d", - chip->effects[i].id); - effect_dir = debugfs_create_dir(str, hap_dir); - if (IS_ERR(effect_dir)) { - rc = PTR_ERR(effect_dir); - dev_err(chip->dev, "create %s debugfs directory failed, rc=%d\n", - str, rc); - goto exit; - } + rc = haptics_add_debugfs(hap_dir, chip->effects, chip->effects_count, "effect"); + if (rc < 0) + goto exit; - rc = haptics_add_effects_debugfs(&chip->effects[i], effect_dir); - if (rc < 0) { - dev_err(chip->dev, "create debugfs nodes for %s failed, rc=%d\n", - str, rc); - goto exit; - } - } + rc = haptics_add_debugfs(hap_dir, chip->primitives, chip->primitives_count, "primitive"); + if (rc < 0) + goto exit; file = debugfs_create_file_unsafe("preload_effect_idx", 0644, hap_dir, chip, &preload_effect_idx_dbgfs_ops); @@ -4138,6 +4184,54 @@ static int haptics_parse_per_effect_dt(struct haptics_chip *chip, return 0; } +static int haptics_parse_primitives_dt(struct haptics_chip *chip) +{ + struct device_node *node = chip->dev->of_node; + struct device_node *child; + int rc, i = 0, num = 0; + + for_each_available_child_of_node(node, child) { + if (of_find_property(child, "qcom,primitive-id", NULL)) + num++; + } + if (!num) + return 0; + + chip->primitives = devm_kcalloc(chip->dev, num, + sizeof(*chip->effects), GFP_KERNEL); + if (!chip->primitives) + return -ENOMEM; + + for_each_available_child_of_node(node, child) { + if (!of_find_property(child, "qcom,primitive-id", NULL)) + continue; + + rc = of_property_read_u32(child, "qcom,primitive-id", &(chip->primitives[i].id)); + if (rc < 0) { + dev_err(chip->dev, "Read qcom,primitive-id failed, rc=%d\n", + rc); + of_node_put(child); + return rc; + } + + rc = haptics_parse_per_effect_dt(chip, child, + &chip->primitives[i]); + if (rc < 0) { + dev_err(chip->dev, "parse primitive %d failed, rc=%d\n", + i); + of_node_put(child); + return rc; + } + i++; + } + + chip->primitives_count = i; + dev_dbg(chip->dev, "Dump primitive effect settings as following\n"); + __dump_effects(chip, chip->primitives, chip->primitives_count); + + return 0; +} + static int haptics_parse_effects_dt(struct haptics_chip *chip) { struct device_node *node = chip->dev->of_node; @@ -4160,6 +4254,14 @@ static int haptics_parse_effects_dt(struct haptics_chip *chip) if (!of_find_property(child, "qcom,effect-id", NULL)) continue; + rc = of_property_read_u32(child, "qcom,effect-id", &(chip->effects[i].id)); + if (rc < 0) { + dev_err(chip->dev, "Read qcom,effect-id failed, rc=%d\n", + rc); + of_node_put(child); + return rc; + } + rc = haptics_parse_per_effect_dt(chip, child, &chip->effects[i]); if (rc < 0) { @@ -4172,7 +4274,8 @@ static int haptics_parse_effects_dt(struct haptics_chip *chip) } chip->effects_count = i; - __dump_effects(chip); + dev_dbg(chip->dev, "Dump predefined effect settings as following\n"); + __dump_effects(chip, chip->effects, chip->effects_count); return 0; } @@ -4470,6 +4573,13 @@ static int haptics_parse_dt(struct haptics_chip *chip) goto free_pbs; } + rc = haptics_parse_primitives_dt(chip); + if (rc < 0) { + dev_err(chip->dev, "Parse device-tree for primitives failed, rc=%d\n", + rc); + goto free_pbs; + } + return 0; free_pbs: if (chip->pbs_node) { @@ -5153,10 +5263,48 @@ static ssize_t lra_impedance_show(struct class *c, } static CLASS_ATTR_RO(lra_impedance); +static ssize_t primitive_duration_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->primitive_duration); +} + +static ssize_t primitive_duration_store(struct class *c, + struct class_attribute *attr, const char *buf, size_t count) +{ + struct haptics_chip *chip = container_of(c, + struct haptics_chip, hap_class); + u16 primitive_id = 0; + int i = 0; + + if (kstrtou16(buf, 0, &primitive_id)) + return -EINVAL; + + for (i = 0; i < chip->primitives_count; i++) { + if (chip->primitives[i].id == primitive_id) + break; + } + + if (i == chip->primitives_count) { + pr_err("Primitive id specified is incorrect\n"); + return -EINVAL; + } + + chip->primitive_duration = get_play_length_effect_us(&chip->primitives[i]); + + return count; +} + +static CLASS_ATTR_RW(primitive_duration); + static struct attribute *hap_class_attrs[] = { &class_attr_lra_calibration.attr, &class_attr_lra_frequency_hz.attr, &class_attr_lra_impedance.attr, + &class_attr_primitive_duration.attr, NULL, }; ATTRIBUTE_GROUPS(hap_class); @@ -5287,15 +5435,15 @@ static int haptics_probe(struct platform_device *pdev) input_set_capability(input_dev, EV_FF, FF_CONSTANT); input_set_capability(input_dev, EV_FF, FF_GAIN); - if (chip->effects_count != 0) { + 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); } - if (chip->effects_count < MAX_EFFECT_COUNT) - count = chip->effects_count + 1; - else - count = MAX_EFFECT_COUNT; + if (chip->effects_count + chip->primitives_count > MAX_EFFECT_COUNT) + dev_err(chip->dev, "Effects count cannot be more than %d\n", MAX_EFFECT_COUNT); + + count = min_t(u32, chip->effects_count + chip->primitives_count + 1, MAX_EFFECT_COUNT); rc = input_ff_create(input_dev, count); if (rc < 0) { @@ -5356,8 +5504,44 @@ static int haptics_remove(struct platform_device *pdev) return 0; } +static void haptics_ds_suspend_config(struct device *dev) +{ + struct haptics_chip *chip = dev_get_drvdata(dev); + + if (chip->fifo_empty_irq > 0) + devm_free_irq(dev, chip->fifo_empty_irq, chip); +} + +static int haptics_ds_resume_config(struct device *dev) +{ + struct haptics_chip *chip = dev_get_drvdata(dev); + int rc = 0; + + rc = haptics_hw_init(chip); + if (rc < 0) { + dev_err(chip->dev, "Initialize HW failed, rc = %d\n", rc); + return rc; + } + + if (chip->fifo_empty_irq > 0) { + rc = devm_request_threaded_irq(chip->dev, chip->fifo_empty_irq, + NULL, fifo_empty_irq_handler, + IRQF_ONESHOT, "fifo-empty", chip); + if (rc < 0) { + dev_err(chip->dev, "request fifo-empty IRQ failed, rc=%d\n", + rc); + return rc; + } + + disable_irq_nosync(chip->fifo_empty_irq); + chip->fifo_empty_irq_en = false; + } + + return rc; +} + #ifdef CONFIG_PM_SLEEP -static int haptics_suspend(struct device *dev) +static int haptics_suspend_config(struct device *dev) { struct haptics_chip *chip = dev_get_drvdata(dev); struct haptics_play_info *play = &chip->play; @@ -5402,16 +5586,74 @@ static int haptics_suspend(struct device *dev) return haptics_module_enable(chip, false); } +static int haptics_suspend(struct device *dev) +{ + struct haptics_chip *chip = dev_get_drvdata(dev); + int rc = 0; + + if (chip->cfg_revision == HAP_CFG_V1) + return 0; + + rc = haptics_suspend_config(dev); + if (rc < 0) + return rc; + +#ifdef CONFIG_DEEPSLEEP + if (mem_sleep_current == PM_SUSPEND_MEM) + haptics_ds_suspend_config(dev); +#endif + + return 0; +} + static int haptics_resume(struct device *dev) { struct haptics_chip *chip = dev_get_drvdata(dev); +#ifdef CONFIG_DEEPSLEEP + if (mem_sleep_current == PM_SUSPEND_MEM) { + int rc = 0; + + rc = haptics_ds_resume_config(dev); + if (rc < 0) + return rc; + } +#endif + return haptics_module_enable(chip, true); } #endif +static int haptics_freeze(struct device *dev) +{ + int rc = 0; + + rc = haptics_suspend_config(dev); + if (rc < 0) + return rc; + + haptics_ds_suspend_config(dev); + + return 0; +} + +static int haptics_restore(struct device *dev) +{ + struct haptics_chip *chip = dev_get_drvdata(dev); + int rc = 0; + + rc = haptics_ds_resume_config(dev); + if (rc < 0) + return rc; + + return haptics_module_enable(chip, true); +} + static const struct dev_pm_ops haptics_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(haptics_suspend, haptics_resume) + .suspend = haptics_suspend, + .resume = haptics_resume, + .freeze = haptics_freeze, + .restore = haptics_restore, }; static const struct of_device_id haptics_match_table[] = {