From 96b9f048281ba123def1c02077216cdc4b2a399e Mon Sep 17 00:00:00 2001 From: Weilong Wu Date: Thu, 28 Mar 2019 14:15:09 +0800 Subject: [PATCH] aw8695: support moto vibrator feature Moto vibrator feature can make vibrations synchronize with the rhythmn of the ringtone. Optimize awinic vibrator driver to support it. Change-Id: If03ad468cba963afef519dc23486cbe80b06f120 Signed-off-by: Weilong Wu Reviewed-on: https://gerrit.mot.com/1328934 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Reviewed-by: Wen Xie Reviewed-by: Huosheng Liao Submit-Approved: Jira Key (cherry picked from commit fcf020fbd1c8a588e6c1e83df05751722bf94f17) Reviewed-on: https://gerrit.mot.com/1365543 Reviewed-by: Guobin Zhang --- drivers/misc/awinic/aw8695/aw8695.c | 213 ++++++++++++++++++++++------ drivers/misc/awinic/aw8695/aw8695.h | 10 ++ 2 files changed, 183 insertions(+), 40 deletions(-) diff --git a/drivers/misc/awinic/aw8695/aw8695.c b/drivers/misc/awinic/aw8695/aw8695.c index f0193c31e438..bca43a5bfb00 100644 --- a/drivers/misc/awinic/aw8695/aw8695.c +++ b/drivers/misc/awinic/aw8695/aw8695.c @@ -41,7 +41,7 @@ #define AW8695_I2C_NAME "aw8695_haptic" #define AW8695_HAPTIC_NAME "aw8695_haptic" -#define AW8695_VERSION "v1.3.4" +#define AW8695_VERSION "v1.3.5" #define AWINIC_RAM_UPDATE_DELAY @@ -56,7 +56,7 @@ #define AW8695_MAX_FIRMWARE_LOAD_CNT 20 - +#define AW8695_SEQ_NO_RTP_BASE 102 /****************************************************** * * variable @@ -66,8 +66,49 @@ static char *aw8695_ram_name = "aw8695_haptic.bin"; static char aw8695_rtp_name[][AW8695_RTP_NAME_MAX] = { {"aw8695_rtp.bin"}, - {"aw8695_rtp_lighthouse.bin"}, - {"aw8695_rtp_silk.bin"}, + {"aw8695_rtp_Argo_Navis.bin"}, + {"aw8695_rtp_Attentive.bin"}, + {"aw8695_rtp_Awake.bin"}, + {"aw8695_rtp_Bird_Loop.bin"}, + {"aw8695_rtp_Brilliant_Times.bin"}, + {"aw8695_rtp_Chimey_Phone.bin"}, + {"aw8695_rtp_Complex.bin"}, + {"aw8695_rtp_Crazy_Dream.bin"}, + {"aw8695_rtp_Curve_Ball_Blend.bin"}, + {"aw8695_rtp_Digital_Phone.bin"}, + {"aw8695_rtp_Electrovision.bin"}, + {"aw8695_rtp_Ether_Shake.bin"}, + {"aw8695_rtp_Fateful_Words.bin"}, + {"aw8695_rtp_Flutey_Phone.bin"}, + {"aw8695_rtp_Future_Funk.bin"}, + {"aw8695_rtp_Future_Hi_Tech.bin"}, + {"aw8695_rtp_Girtab.bin"}, + {"aw8695_rtp_Hello.bin"}, + {"aw8695_rtp_Hexagon.bin"}, + {"aw8695_rtp_Hydra.bin"}, + {"aw8695_rtp_Insert_Coin.bin"}, + {"aw8695_rtp_Jumping_Dots.bin"}, + {"aw8695_rtp_Keys.bin"}, + {"aw8695_rtp_Loopy.bin"}, + {"aw8695_rtp_Loopy_Lounge.bin"}, + {"aw8695_rtp_Modular.bin"}, + {"aw8695_rtp_Momentum.bin"}, + {"aw8695_rtp_Morning.bin"}, + {"aw8695_rtp_Moto.bin"}, + {"aw8695_rtp_Natural.bin"}, + {"aw8695_rtp_New_Player.bin"}, + {"aw8695_rtp_Onward.bin"}, + {"aw8695_rtp_Organ_Dub.bin"}, + {"aw8695_rtp_Overclocked.bin"}, + {"aw8695_rtp_Pegasus.bin"}, + {"aw8695_rtp_Pyxis.bin"}, + {"aw8695_rtp_Regrade.bin"}, + {"aw8695_rtp_Scarabaeus.bin"}, + {"aw8695_rtp_Sceptrum.bin"}, + {"aw8695_rtp_Simple.bin"}, + {"aw8695_rtp_Solarium.bin"}, + {"aw8695_rtp_Sparse.bin"}, + {"aw8695_rtp_Terrabytes.bin"}, }; struct aw8695_container *aw8695_rtp; @@ -80,7 +121,7 @@ struct aw8695 *g_aw8695; ******************************************************/ static void aw8695_interrupt_clear(struct aw8695 *aw8695); static int aw8695_haptic_trig_enable_config(struct aw8695 *aw8695); - +static void aw8695_vibrate(struct aw8695 *aw8695, int value); /****************************************************** * @@ -1747,6 +1788,110 @@ static int aw8695_haptic_init(struct aw8695 *aw8695) * vibrator * *****************************************************/ + +static void aw8695_rtp_play(struct aw8695 *aw8695, int value) +{ + aw8695_haptic_stop(aw8695); + aw8695_haptic_set_rtp_aei(aw8695, false); + aw8695_interrupt_clear(aw8695); + if (value < (sizeof(aw8695_rtp_name) / AW8695_RTP_NAME_MAX)) { + aw8695->rtp_file_num = value; + if (value) { + schedule_work(&aw8695->rtp_work); + } + } else { + pr_err("%s: rtp_file_num 0x%02x over max value \n", __func__, aw8695->rtp_file_num); + } +} + +#if 0 +static void aw8695_haptic_context(struct aw8695 *aw8695, enum aw8695_haptic_mode cmd) +{ + int t_top = 0; + if (!gpio_is_valid(aw8695->haptic_context_gpio)) { + pr_debug("%s haptic context gpio is invalid \n", __func__); + return; + } + + t_top = gpio_get_value(aw8695->haptic_context_gpio); + if (t_top && atomic_read(&aw8695->reduce_pwr)) { + switch (cmd) { + case HAPTIC_RTP: + aw8695->gain = 0x20; + break; + case HAPTIC_SHORT: + aw8695->gain = 0x20; + break; + case HAPTIC_LONG: + aw8695->gain = 0x06; + break; + default: + break; + } + } +} +#endif + +static void aw8695_vibrate(struct aw8695 *aw8695, int value) +{ + int seq = 0; + mutex_lock(&aw8695->lock); + + aw8695_haptic_stop(aw8695); + seq = aw8695->seq[0]; + pr_info("%s: value=%d, seq=%d\n", __FUNCTION__, value, seq); + + if (value > 0 || seq > 2) { + + if (seq >= AW8695_SEQ_NO_RTP_BASE) { + aw8695->haptic_mode = HAPTIC_RTP; + } else if (value < 100 || seq > 2) { + aw8695->haptic_mode = HAPTIC_SHORT; + } else { + aw8695->haptic_mode = HAPTIC_LONG; + } + + switch (aw8695->haptic_mode) { + + case HAPTIC_RTP: + aw8695_rtp_play(aw8695, seq - AW8695_SEQ_NO_RTP_BASE); + break; + case HAPTIC_SHORT: + if (aw8695->seq[0] == 0) + aw8695->seq[0] = 0x01; + aw8695_haptic_set_wav_seq(aw8695, 0x00, aw8695->seq[0]); + aw8695_haptic_set_wav_loop(aw8695, 0x00, 0x00); + aw8695_haptic_ram_vbat_comp(aw8695, false); + aw8695_haptic_play_wav_seq(aw8695, 0x01); + break; + case HAPTIC_LONG: + aw8695->duration = value; + /* wav index config */ + aw8695->index = 0x02; + aw8695_haptic_set_repeat_wav_seq(aw8695, aw8695->index); + //__pm_wakeup_event(aw8695->ws, value + 100); + /* run ms timer */ + hrtimer_cancel(&aw8695->timer); + aw8695->state = 0x01; + if (aw8695->state) + { + hrtimer_start(&aw8695->timer, + ktime_set(aw8695->duration / 1000, (value % 1000) * 1000000), + HRTIMER_MODE_REL); + } + schedule_work(&aw8695->vibrator_work); + break; + default: + break; + } + + /* Restore to default short waveform */ + if (seq > 2) + aw8695->seq[0] = 0; + } + + mutex_unlock(&aw8695->lock); +} #ifdef TIMED_OUTPUT static int aw8695_vibrator_get_time(struct timed_output_dev *dev) { @@ -1902,6 +2047,7 @@ static ssize_t aw8695_activate_store(struct device *dev, struct led_classdev *cdev = dev_get_drvdata(dev); struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); #endif + unsigned int val = 0; int rc = 0;; @@ -1912,23 +2058,12 @@ static ssize_t aw8695_activate_store(struct device *dev, if (val != 0 && val != 1) return count; - pr_debug("%s: value=%d\n", __FUNCTION__, val); - - mutex_lock(&aw8695->lock); - hrtimer_cancel(&aw8695->timer); - + pr_info("%s: value=%d\n", __FUNCTION__, val); aw8695->state = val; - - if (aw8695->state) { - /* clip value to max */ - val = aw8695->duration; - /* run ms timer */ - hrtimer_start(&aw8695->timer, - ktime_set(val / 1000, (val % 1000) * 1000000), - HRTIMER_MODE_REL); - } - mutex_unlock(&aw8695->lock); - schedule_work(&aw8695->vibrator_work); + if (aw8695->state) + aw8695_vibrate(aw8695, aw8695->duration); + else + aw8695_vibrate(aw8695, 0); return count; } @@ -2125,16 +2260,24 @@ static ssize_t aw8695_seq_store(struct device *dev, struct led_classdev *cdev = dev_get_drvdata(dev); struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); #endif - unsigned int databuf[2] = {0, 0}; - if (2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) { - pr_debug("%s: seq%d=0x%x\n", __FUNCTION__, databuf[0], databuf[1]); - mutex_lock(&aw8695->lock); - aw8695->seq[databuf[0]] = (unsigned char)databuf[1]; - aw8695_haptic_set_wav_seq(aw8695, (unsigned char)databuf[0], - aw8695->seq[databuf[0]]); - mutex_unlock(&aw8695->lock); + unsigned int i = 0; + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + pr_info("%s: value=%x\n", __FUNCTION__, val); + + mutex_lock(&aw8695->lock); + for(i=0; i<4; i++) { + aw8695->seq[i] = (val>>((AW8695_WAV_SEQ_SIZE-i-1)*8)) & 0xFF; + aw8695_haptic_set_wav_seq(aw8695, i, aw8695->seq[i]); } + mutex_unlock(&aw8695->lock); + return count; } @@ -2263,17 +2406,7 @@ static ssize_t aw8695_rtp_store(struct device *dev, struct device_attribute *att if (rc < 0) return rc; - aw8695_haptic_stop(aw8695); - aw8695_haptic_set_rtp_aei(aw8695, false); - aw8695_interrupt_clear(aw8695); - if (val < (sizeof(aw8695_rtp_name) / AW8695_RTP_NAME_MAX)) { - aw8695->rtp_file_num = val; - if (val) { - schedule_work(&aw8695->rtp_work); - } - } else { - pr_err("%s: rtp_file_num 0x%02x over max value \n", __func__, aw8695->rtp_file_num); - } + aw8695_rtp_play(aw8695, val); return count; } diff --git a/drivers/misc/awinic/aw8695/aw8695.h b/drivers/misc/awinic/aw8695/aw8695.h index d48d750904d2..f687fae2d6a7 100644 --- a/drivers/misc/awinic/aw8695/aw8695.h +++ b/drivers/misc/awinic/aw8695/aw8695.h @@ -36,6 +36,7 @@ #define AW8695_REG_MAX 0xff +#define AW8695_WAV_SEQ_SIZE 4 #define AW8695_SEQUENCER_SIZE 8 #define AW8695_SEQUENCER_LOOP_SIZE 4 @@ -221,6 +222,12 @@ enum aw8695_haptic_pwm_mode { AW8695_PWM_12K = 2, }; +enum aw8695_haptic_mode{ + HAPTIC_NONE = 0x00, + HAPTIC_SHORT = 0x01, + HAPTIC_LONG = 0x02, + HAPTIC_RTP = 0x03, +}; /********************************************************* * * struct @@ -290,7 +297,10 @@ struct aw8695 { int reset_gpio; int irq_gpio; + int haptic_context_gpio; + enum aw8695_haptic_mode haptic_mode; + atomic_t reduce_pwr; unsigned char hwen_flag; unsigned char flags; unsigned char chipid;